CF1778D Flexible String Revisit

CF1778D Flexible String Revisit

题目大意

给出两个长度均为 n n n的01序列 S S S T T T,每次随机将 S S S中的某一位取反,求第一次 S = T S=T S=T时期望的操作次数。

有多组数据。


题解

因为是随机取反的,所以我们只需要知道 S S S T T T中相等的位的数量和不相等的位的数量。

f i f_i fi表示未匹配的位的数量为 i i i,翻转序列 S S S中不匹配的位置的期望操作次数。

考虑转移。每次有 i n \dfrac in ni的概率旋转一个不匹配的字符,有 n − i n \dfrac{n-i}{n} nni的概率翻转一个已匹配的字符。翻转已匹配的字符后需要 f i + 1 f_{i+1} fi+1的期望操作次数才能回到当前状态,然后还需要 f i f_i fi的期望操作次数才能再翻转一个未匹配字符,那么

f i = i n × 1 + n − i n × ( 1 + f i + 1 + f i ) f_i=\dfrac in\times 1+\dfrac{n-i}{n}\times (1+f_{i+1}+f_i) fi=ni×1+nni×(1+fi+1+fi)

化简得

f i = n + ( n − i ) f i + 1 i f_i=\dfrac{n+(n-i)f_{i+1}}{i} fi=in+(ni)fi+1

当然, f n = 1 f_n=1 fn=1,因为在这种情况下无论怎么翻转,都会翻转一个未匹配字符。

设当前有 k k k个字符未匹配,那么答案为 f k + f k − 1 + ⋯ + f 1 f_k+f_{k-1}+\cdots+f_{1} fk+fk1++f1

时间复杂度为 O ( ∑ n ) O(\sum n) O(n)。当然,如果提前处理 f f f数组,那么时间复杂度可以达到 O ( m x n + t ) O(mxn+t) O(mxn+t),mxn表示输入中最大的 n n n

code

#include<bits/stdc++.h>
using namespace std;
int t,n,v;
char a[1000005],b[1000005];
long long ans,f[1000005];
long long mod=998244353;
long long mi(long long t,long long v){
	if(!v) return 1;
	long long re=mi(t,v/2);
	re=re*re%mod;
	if(v&1) re=re*t%mod;
	return re;
}
int main()
{
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		scanf("%s%s",a,b);
		v=0;
		for(int i=0;i<=n;i++) f[i]=0;
		for(int i=0;i<n;i++){
			if(a[i]!=b[i]) ++v;
		}
		f[n]=1;
		for(int i=n-1;i>=1;i--){
			f[i]=(n+(n-i)*f[i+1])%mod*mi(i,mod-2)%mod;
		}
		ans=0;
		for(int i=v;i>=1;i--){
			ans=(ans+f[i])%mod;
		}
		printf("%lld\n",ans);
	}
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值