Codeforces Round #848 (Div. 2)D. Flexible String Revisit-dp、初等数学

题目:https://codeforces.com/problemset/problem/1778/D

场内打的,首先很容易想到答案来自于a、b不同的位置有几个,设\(f_k\)表示当前有k个不同的位置要复原到完全一样需要多少操作,则\(f_k=\frac{k}{n} f_{k-1}+\frac{n-k}{n}f_{k+1}+1\),边界\(f_0=0\),以及特殊的\(f_n=1+f_{n-1}\)

赛时我还企图去做一个递推发现有点行不通,毕竟只是div2的D题应该也用不上什么数学技巧,所以其实盯着边界,考虑设\(f_k=f_{k-1}+x_k\),则\(x_n=1\),然后\(f_k=\frac{k}{n}f_{k-1}+1+\frac{n-k}{n}(f_k+x_{k+1})\),就得到\(x_k=\frac{n}{k}(1+\frac{n-k}{n} x_{k+1})\),然后这样就可以递推出\(x_1\),然后得到\(f_1\),进一步就可以递推了

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define endl '\n'
typedef long long ll;
using namespace std;
const int MOD=998244353;
const int N=1e6+5;
ll ksm(ll a,ll b){
	ll ret=1;a%=MOD; 
	for(;b;b>>=1,a=a*a%MOD)if(b&1)ret=ret*a%MOD;
	return ret;
}
ll inv(ll x){return ksm(x,MOD-2);}
int n;
string a,b;
ll f[N],x[N];
int main(){
	int T;cin>>T;
	while(T--){
		cin>>n>>a>>b;
		int cnt=0;
		rep(i,0,n-1)if(a[i]!=b[i])cnt++;
		x[n]=1;
		for(int i=n-1;i>=1;i--)x[i]=(1ll*(n-i)*inv(i)%MOD*x[i+1]%MOD+1ll*n*inv(i)%MOD)%MOD;
		f[0]=0;f[1]=x[1];
		rep(i,1,n-1)f[i+1]=(1ll*n*f[i]%MOD+(MOD-1ll*i*f[i-1]%MOD)%MOD+MOD-n)%MOD*inv(n-i)%MOD;
		cout<<f[cnt]<<endl;
	}
	return 0;
}
posted @ 2023-02-05 19:22  yoshinow2001  阅读(49)  评论(0编辑  收藏  举报