CF176B Word Cut

CF176B Word Cut

挺厉害的一道题,做一些补充说明。

果然还是数数题不是很行。

首先可以观察到一点,对于一个字符,他在任何位置,他转一圈回来所得到的字符串是不会变化的,因为相对的顺序并没有改变。(其实可以手玩出来。)

所以就可以得到,这做了 kk 次操作,就相当于只做了一次操作。(也就是最后一次)。

所以现在要解决,在 所有和 SS 构成循环同构的字符串中,找到和 TT 相等的字符串,把 SS 复制一次跑字符串匹配即可,设符合的位置有 xx 个。

因为对于一个字符,在哪个位置操作对构成的字符串都没有影响。所以不妨在 TT 上操作,因为这样可以避免掉 SS 的第一个字符不能转的问题。且处理来的 xx 个位置,在 TT 中同样符合转一次,和 TT 重合的条件。

然后就设 dpi,0/1dp_{i,0/1} 表示转了 ii 次,和 TT 一样的种类,以及转出来其他串的情况。

转移就是:

dpi,0=dpi1,0×(x1)+dpi1,1×xdp_{i,0}=dp_{i-1,0}\times (x-1)+dp_{i-1,1}\times x dpi,1=dpi1,0×(nx)+dpi1,1×(nx1)dp_{i,1}=dp_{i-1,0}\times (n-x)+dp_{i-1,1}\times (n-x-1)

在这里主要是注意一下不能从开头来转(因为没有位置可以断了),所以要减去 11,不然就是不操作,那就不合法了。

#include<bits/stdc++.h>
using namespace std;
const int N =1e6+10;
const int mod=1e9+7;
#define int long long 
int k,f[N],dp[N][2],cnt,n;
char s[N],t[N];
void init(){
	f[0]=-1;
	int i=1,j=-1;
	while(i<=n){
		while(j!=-1&&t[i]!=t[j+1])	j=f[j];
		f[i++]=++j;
	}
}
void KMP(){
	int j=0;
	for(int i=1;i<=strlen(s+1);i++){
		while(j!=-1&&t[j+1]!=s[i])	j=f[j];
		j++;
		if(j==n&&i-n+1<=n)	cnt++;
	}
}
signed main(){
	scanf("%s%s%d",s+1,t+1,&k);
	string a=s+1,b=t+1;
	if(a==b)	dp[0][0]=1;
	else	dp[0][1]=1;
	n=strlen(s+1);
	for(int i=1;i<=n;i++)	s[i+n]=s[i];
	init(),KMP();
	for(int i=1;i<=k;i++){
		dp[i][0]+=(dp[i-1][0]%mod*(cnt-1)%mod+dp[i-1][1]%mod*cnt%mod)%mod;
		dp[i][1]+=((dp[i-1][0]%mod*(n-cnt)%mod)+(dp[i-1][1]%mod*(n-cnt-1)%mod))%mod;
		dp[i][0]%=mod,dp[i][1]%=mod;
	}
	cout<<dp[k][0]<<endl;
}
posted @   June_Failure  阅读(0)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示