首页 > 其他分享 >Day-7 模拟赛题解

Day-7 模拟赛题解

时间:2024-02-21 22:13:30浏览次数:23  
标签:10 int 题解 len long ans Day 模拟 MOD

Day-7 模拟赛题解

T1

数据点 3 - 5

  • 枚举每一个问号对应的字母
  • Kmp,把 s 当作模式串匹配 T
  • \(O(26^k|T|)\),k 是 ? 的个数
代码(我也不知道为啥 T 了,鸽着)

正解

  • 有种被诈骗了的感觉
  • 根据期望的可加性,答案等于各个字符串出现次数的期望的和
    • 于是,各个字符串出现在哪里相互没有关联
    • 于是,枚举每个字符串出现的位置,单独计算期望,累加
  • 设字符串 S = T[i, j] 中有 \(k_0\) 个 ?,则他的期望 = \(\frac{26^{(k - k_0)}}{26^k}\)
  • 复杂度 \(O(n^2)\)
    • \(\sum len_s \le 3e5\),所以枚举起点 \(O(n)\),每个起点每个 S 都访问一次 \(O(n)\),相乘
    • 这是一个均摊复杂度
  • 注:string 超级慢!! 用 char 不容易被卡
代码
# include <bits/stdc++.h>
# define int long long
# define double long double
using namespace std;
const int MOD = 998244353;
const int N = (int)5e3 + 10;

int q, n;
int poww[N];
char s[N], t[N];

int Q_pow(int a, int b){
	int ans = 1, p = a;
	while(b){
		if(b & 1){
			ans = (ans * p) % MOD;
		}
		b >>= 1;
		p = (p * p) % MOD;
	}
	return ans;
}

signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);	
	
	int up = 5000;
	poww[0] = 1;
	for(int i = 1; i <= up; i++){
		poww[i] = poww[i - 1] * 26 % MOD;
	}
	
	cin >> q;
	while(q--){
		cin >> t >> n;		
		int k = 0;
		for(auto i : t){
			if(i == '?'){
				k++;
			}
		}
		
		int len = strlen(t), ans = 0;
		for(int i = 1; i <= n; i++){
			cin >> s;
			int lenn = strlen(s), up = len - lenn + 1;
			for(int j = 0; j < up; j++){
				bool f = 1;
				int temp = k;
				for(int k = 0; k < lenn; k++){
					if(t[j + k] != '?' && s[k] != t[j + k]){
						f = 0;
						break;
					}
					if(t[j + k] == '?'){
						temp--;
					}
				}
				if(f == 1){
					ans = (ans + poww[temp]) % MOD;
				}
			}
		}
		ans = ans * Q_pow(poww[k], MOD - 2) % MOD;
		cout << ans << "\n";
	}
}

T2

  • 均摊时间复杂度坑爹啊!

    • 每组数字只会被加进去 && 删除 1 次,均摊 \(O(n)\)
    • 而我费尽心思线段树 + 二分加上去两个 log
  • 设原来拼成的数字是 c (考虑操作带来的影响

    • 加入:\(c -> c * 10 ^ x + y_0\)
    • 删除:\(c -> c - 10^{(len - x)} * y_0\)
    • len 为 c 的长度,\(y_0\) 为 x 个 y 构成的数
  • 如何求 \(y_0\)

    • 小学奥数
    • \(y * 10 ^ 0 + y * 10 ^ 1 + ... + y * 10 ^ {n - 1} = y_0\)
    • \(y * 10 ^ 1 + y * 10 ^ 2 + ... + y * 10 ^ n = 10 * y_0\)
    • \(9 * y_0 = y * (10 ^ n - 1)\)
    • \(y_0 = \frac{y*(10^n - 1)}{9}\)
  • 对于 \(10 ^ n\),常规方法是快速幂,但是 5e6 带 log 跑不过

    • 光速幂
光速幂
  • 能做到单次询问 \(O(1)\)

  • 对于 \(a^b\),设 \(b = p * q + r, r \le q\)

  • 则 \(a^b = (a^p)^q * a^r\)

  • 我们要做的就是预处理 \(a^p, a^r\)

    • 当 \(p = sqrt(mod)\) 时预处理为\(O(sqrt(n))\),时间复杂度最小
    • 预处理出 \(r = 1 到 sqrt(mod), q = 1 到 sqrt(mod)\) 时的 \(a^k\),在 1e4 - 1e5 级别
  • 根据欧拉定理 \(a ^ b ≡ a^{b \% \phi(mod)}(\% mod)\),这可以缩小 b 的范围到 [0, mod] 中

  • 完事!

代码
  • 出题人卡我输入输出!!
  • 不过快读是真快!!
# include <bits/stdc++.h>
# define int long long
# define double long double
using namespace std;
const int INV = 443664157; // INV 9
const int MOD = 998244353;
const int N = (int)1e7 + 10;

int n;
int opt, x, y;
struct Node{
	int x, y;
}a[N];
int l, r, val, len;

int read(){
	int sum=0,f=1;char st=getchar();
	while(st<'0'||st>'9'){
		if(st=='-')f=-1;
		st=getchar();
	}
	while('0'<=st&&st<='9'){
		sum=(sum<<3)+(sum<<1)+st-'0';
		st=getchar();
	}
	return sum*f;
}

int p, phi, base = 10, pw[N][2];

int Phi(int x){
	int ans = x;
	for(int i = 2; i * i <= x; i++){
		if(x % i == 0){
			ans = ans / i * (i - 1);
			while(x % i == 0){
				x /= i;
			}
		}
	}
	if(x > 1){
		ans = ans / x * (x - 1);
	}
	return ans;
}

void Init(){
	phi = Phi(MOD);
	p = sqrt(MOD);
	pw[0][0] = pw[0][1] = 1;
	for(int i = 1; i <= p; i++){
		pw[i][0] = pw[i - 1][0] * base % MOD;
	}
	for(int i = 1; i <= p; i++){
		pw[i][1] = pw[i - 1][1] * pw[p][0] % MOD;
	}
}

int Query(int b){
	b %= phi;
	return pw[b % p][0] * pw[b / p][1] % MOD;
} 

signed main(){
	n = read();
	Init();
	
	l = r = val = len = 1;
	a[1] = {1, 1};
	for(int i = 1; i <= n; i++){
		opt = read();
		if(opt == 1){
			x = read(), y = read();
			a[++r] = {x, y};
			len += x;
			val = (val * Query(x) % MOD + y * (Query(x) + MOD - 1) % MOD * INV % MOD) % MOD;
		}else if(opt == 2){
			x = read();
			while(x){
				if(x >= a[l].x){
					val = val + MOD - a[l].y * (Query(a[l].x) + MOD - 1) % MOD * INV % MOD * Query(len - a[l].x) % MOD;
					val %= MOD;
					x -= a[l].x;
					len -= a[l].x;
					l++;
				}else{
					val = val + MOD - a[l].y * (Query(x) + MOD - 1) % MOD * INV % MOD * Query(len - x) % MOD;				
					val %= MOD;
					a[l].x -= x;
					len -= x;
					x = 0;
				}
			}
		}else{
			printf("%lld\n", val);
		}
	}
}

T3

  • 只写 60 分做法,满分做法太阴间了,鸽了
  • 设 dp[i][j] 表示 i 节点及其子树原来无色,强行染成 j 色后还需要几步达到题目要求
  • 对于节点 i,\(mini = min(\sum_{i = [0, n]} dp[son][i])\)
    • 如果 \(\sum_{i = [0, n]} dp[son][i] == mini\),dp[i][j] = mini
    • 否则,dp[i][j] = mini + 1
      • 即:先用 1 步把 i 及其子树染成 j,再一股脑染成 mini 对应的颜色
      • 这样比 mini 多用 1 步
  • 注:全局定义的数组在递归中调用时要注意
    • 不要 i 调用了又在 \(son_i\) 调用(除非需要这么做)
代码
# include <bits/stdc++.h>
# define int long long
# define double long double
using namespace std;
const int N = 5e3 + 10;

int n;
int fa, a[N];
int maxc, sumc[N], dp[N][N];
vector <int> e[N];

void Dfs(int x){
	if(a[x] != 0){
		for(int i = 0; i <= maxc; i++){
			dp[x][i] = (a[x] != i);
		}	
	}else{
		for(auto i : e[x]){
			Dfs(i);
		}
		for(int i = 0; i <= maxc; i++){
			sumc[i] = 0;
		}
		for(auto i : e[x]){
			for(int j = 0; j <= maxc; j++){
				sumc[j] += dp[i][j];
			}
		}
		int mini = (int)1e18;
		for(int i = 0; i <= maxc; i++){
			mini = min(mini, sumc[i]);
		}
		for(int i = 0; i <= maxc; i++){
			if(sumc[i] == mini){
				dp[x][i] = mini;
			}else{
				dp[x][i] = mini + 1;
			}
		}
	}
}

signed main(){
	cin >> n;
	for(int i = 2; i <= n; i++){
		cin >> fa;
		e[fa].push_back(i);
	}
	for(int i = 1; i <= n; i++){
		cin >> a[i];
		maxc = max(maxc, a[i]);
	}
	Dfs(1);
	cout << dp[1][0] << "\n";
}

T4

  • 鸽了

标签:10,int,题解,len,long,ans,Day,模拟,MOD
From: https://www.cnblogs.com/wangyangjena/p/18026303

相关文章

  • 代码随想录 day57 最长公共子序列 不相交的线 最大子数组和
    最长公共子序列dp[i][j]:长度为[0,i-1]的字符串text1与长度为[0,j-1]的字符串text2的最长公共子序列为dp[i][j]主要就是两大情况:text1[i-1]与text2[j-1]相同,text1[i-1]与text2[j-1]不相同如果text1[i-1]与text2[j-1]相同,那么找到了一个公共元素,所以dp......
  • day38 动态规划part1 代码随想录算法训练营 746. 使用最小花费爬楼梯
    题目:746.使用最小花费爬楼梯我的感悟:哈哈,我居然自己独立写出来了,确实,只要定义定清楚了,哪怕定的含义只有自己能看懂,只要定义一致就可以求出解决来!!!我真是个大天才!!理解难点:听课笔记:代码示例:classSolution:defminCostClimbingStairs(self,cost:List[int])->int:......
  • 2024初三集训模拟测试3
    T1排序读完题就切了。T2牛吃草点击查看题目很明显的单调队列优化DP。T3树上的宝藏先不考虑对边进行修改,树形DP处理出每个节点的相关信息。转移感觉有些像前几天的CF1929D。设\(f_{i,0/1}\)表示以\(i\)为根节点的子树内是否选\(i\)的方案数,\(f_{i,2}\)表示以......
  • P10064 [SNOI2024] 公交线路 题解
    非常好题目。思路可以发现限制最严的一定是两个叶子的联通性。我们不妨把一个叶子向外起到联通性作用的路径称为有用的路径。也就是这个叶子走这条路径一定可以两步以内到达任意点。这个路径集合有什么作用呢。有一个性质:整个集合的路径的交最终会形成一个连通块。那么我们......
  • # 代码随想录算法训练营day01 | leetcode 704. 二分查找、35.搜索插入位置、34.在排序
    题目链接:704.二分查找-简单题目描述:给定一个n个元素有序的(升序)整型数组nums和一个目标值target,写一个函数搜索nums中的target,如果目标值存在返回下标,否则返回-1。示例1:输入:nums=[-1,0,3,5,9,12],target=9输出:4解释:9出现在nums中并且下标为4示......
  • Atm/抢掠计划——题解
    题目描述样例671223352441266510128161514435647解析题目明显是最长路,可以用spfa求最长路,但数据范围5e5明显不允许,所以我们可以用tarjan优化一下,然后这就变成了一道tarjan板子题,先用tarjan缩点,点权为几个点之和,把所有点再存到一个数组中,再按......
  • 2024初三年后集训模拟测试3
    前言比赛链接难度不好说,感觉是东拼西凑的题,但是除了\(T1\)都不简单。\(T1~100pts:\)贪心+四边形不等式。\(T2~70pts:\)读假题了,是最大\(w_i\)不是固定\(w_i\),做法是二分答案+DP,不过需要单调队列优化,不会这玩意儿赛后学了好久\(qwq\)。但是读假题了还能拿......
  • 洛谷P4447题解
    md这篇反正不交题解的,随便写,不管它格式题意简化下,给你N个数,求出连续值分组人数最小的那组的人数最大值。这个题目还挺经典的,原本23年8月份过了到现在来又不会了(划掉,bushi对于这种,很容易想到的是输入,之后排序,然后分组这种模板就不多说了,就在我24年2月份重温这道题再打一遍代码......
  • 爬虫03_days
    selenium介绍#1由于requests不能执行js---》逐个分析ajax请求--》模拟发送获取数据 -使用requests爬取的数据很大概率跟在浏览器中看到的不一样-requests不能执行js#2seleniumselenium最初是一个自动化测试工具,而爬虫中使用它主要是为了解决requests无法直接执行JavaS......
  • day38 动态规划part1 代码随想录算法训练营 70. 爬楼梯
    题目:70.爬楼梯我的感悟:居然自己先写出来了!!继续努力!!理解难点:听课笔记:我的代码:classSolution:defclimbStairs(self,n:int)->int:ifn==1:return1dp=[0]*(n+1)dp[1]=1dp[2]=2foriinran......