专栏文章

题解:CF645E Intellectual Inquiry

CF645E题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minoxit1
此快照首次捕获于
2025/12/02 05:58
3 个月前
此快照最后确认于
2025/12/02 05:58
3 个月前
查看原文
CPP
#include <bits/stdc++.h>
#define mod 1e9 + 7
using namespace std;

int n, m, k, ans;
int f[27], last[27];
void add(int &a, int b)
{
	a += b;
	if (a >= mod)
		a -= mod;
}
int main()
{
	freopen("string.in", "r", stdin);
	freopen("string.out", "w", stdout);
	int i, j, old, x, t;
	char c;
	
	scanf("%d%d", &m, &k);
	ans = 1;
	while (scanf("%c",&c)!=EOF)//所有文件的结尾都是EOF 
	{
//		c=getchar();
		x = c - 'a' + 1;
		if (x < 1 || x > 26) continue; 
		old = ans;
		add(ans, ans);
		add(ans, mod - f[x]);
		f[x] = old;
		last[x] = ++n;
//		c = getchar();
	}
	for (i = 1; i <= m; i++)
	{
		x = 0;
		for (j = 1; j <= k; j++)
			if (!x || last[x] > last[j])
				x = j;
		last[x] = ++n;
		old = ans;
		add(ans, ans);
		add(ans, mod - f[x]);
		f[x] = old; 
	}
	printf("%d", ans);
	return 0;
}

/*
s 是给出的字符串
for(int i=n;i>=1;i--){
	for(int j=1;j<=k;j++) nxt[i][j]=nxt[i+1][j];
	nxt[i][s[i+1]-'a'+1]=i+1;
}


*/


//给一个长度为n的字符串,字符集是前k个小写字母,可以在后面再加m个字母
//问本质不同的子序列最多有多少种
//k=1
//所有字母完全相同(加的m个字母也只能加字母a) 
// n+m个a组成的字符串
//aaaaaaaaaaaaaaaaa
//n+m个本质不同的子序列

//k=1   cout<<n+m<<endl; 


//字符串读入的技巧 
//n=0 scanf("%s",s+1); //RE
//给一个字符串,可能什么也没有,可能有若干字符,怎么读进来 

//找充要条件,去计算本质不同的子序列
//怎么判定一个字符串A是不是另一个字符串B的一个子序列
//aab是不是abbab 
//先找到第一个a字符 a
//再找到后续的第一个a字符 a 走到abba的位置
//再走到后续的第一个b   abbab的这个位置
//一定是每次找到后续的第一个我这个位置的字符 
/*
S,T 判定S是不是T的第一个子序列
int j=1;
for(int i=1;i<=|S|;i++){
	while(T[j]!=S[i]) j++;//找到第一个T[j]=S[i]  
}

*/

//dp[i]表示有多少个字符串S,
//S[1] ,S[2] S[3] S[4],.... S[|S|]   -> T的i这个位置 
 

//思考m=0怎么处理
//不在后面加字符,单纯问一个字符串有多少个本质不同的子序列
//dp[i]表示有多少个子序列不停匹配,已经匹配到了i
//枚举下一个字符是什么? 枚举下一个字符是1~k中的某一个c
//一定会匹配到i后续的第一个c字符
//S[1],....S[|S|] S[|S|+1]=c
//dp[i] -> dp[nxt[i][c]] nxt[i][c] 表示的是i后面的第一个c字符的位置 
//k=26 提前预处理每个i后续对于每个字符c第一次出现的位置nxt[i][c]
//最终答案就是所有dp[1]+dp[2]+...dp[n]  dp[0]=1 

//后面加字符

//枚举前面转移到后面

//枚举i   对于可以转移的j  dp[j]+=dp[i] 

//枚举后面,看看哪些前面的位置可以转过来 
//枚举j   看看哪些i可以转移到j  dp[j]+=dp[i] 

//考虑在后面加字符 
//dp[i] -> dp[nxt[i][c]]
//反过来考虑 dp[x]可以从哪些位置转移过来 
//dp[i] 转移到i后面的第一个c字符假设这个位置是j
//考虑哪些i可以转移到j
//[i+1,j-1] 这一段区间内没有字符s[j]
//abababababxababababx 
//           iiiiiiiij
//从倒过来转移的角度
//j  pre[j][s[j]] 是j之前的第一个s[j]字符位置是什么 
//记录x=pre[j][s[j]] 
//dp[j]=dp[x]+dp[x+1]+dp[x+2]+dp[x+3]+....+dp[j-1]
//通过前缀优化 
//肯定是想找x最小的字符
//pre[j][s[j]]最小的一个位置
//一定会变成距离我最远的那个字符 
//abcdebcdae_-> b
//abcdebcdaeb_-> c
//pre[j][c]最小的这样一个位置,c是我要插入的字符 

评论

0 条评论,欢迎与作者交流。

正在加载评论...