题目大意:给出两个串s,t,n个灯泡的序列,1代表开着,0代表关着,一共操作k轮,每轮改变m个灯泡的状态,问最终能把s串变成t串的方案数。
坤神题解。
很奇特的一种dp,首先状态的定义dp[i][j]是前i轮操作后,有j个灯泡的状态跟最终串不一样的方案数。这样初始化是dp[0][num]=1其他全0,num是s串和t串状态不同的灯泡数目。然后状态的转移,对于每一轮我们枚举有j个灯泡跟最终串状态不一样,然后再枚举上一轮有kk个灯泡与最终串状态不一样,每次操作都会改变灯泡的状态,设上一轮不一样的状态改变了x个,一样的状态改变了y个,那么x,y应该有0<=x<=kk,0<=y<=n-kk,x+y=m,kk-x+y=j,这四个约束条件,而满足约束条件的就是合法的转移过程,也就是dp[i][j]=dp[i-1][kk]*C[kk][x]*C[n-kk][y],最后注意取模。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<cstdio> 2 typedef long long ll; 3 const int N=118,mod=998244353; 4 ll dp[N][N],C[N][N]; 5 char a[N],b[N]; 6 void getC() 7 { 8 C[0][0]=1ll; 9 for(int i=1;i<=100;i++) 10 { 11 C[i][0]=1ll; 12 for(int j=1;j<=i;j++) 13 { 14 if(j<=i/2) 15 C[i][j]=C[i-1][j]+C[i-1][j-1]; 16 else 17 C[i][j]=C[i][i-j]; 18 if(C[i][j]>=mod) 19 C[i][j]%=mod; 20 } 21 } 22 } 23 void init(int n,int k) 24 { 25 for(int i=0;i<=k;i++) 26 for(int j=0;j<=n;j++) 27 dp[i][j]=0ll; 28 int num=0; 29 for(int i=0;i<n;i++) 30 num+=(a[i]!=b[i]); 31 dp[0][num]=1; 32 } 33 int main() 34 { 35 int t,n,m,k,x,y; 36 getC(); 37 scanf("%d",&t); 38 while(t--) 39 { 40 scanf("%d%d%d",&n,&k,&m); 41 scanf("%s%s",a,b); 42 init(n,k); 43 for(int i=1;i<=k;i++) 44 for(int j=0;j<=n;j++) 45 for(int kk=((m+j)&1);kk<=m+j&&kk<=n;kk+=2) 46 {//把约束条件联立一下可以得出合法条件下的x,y 47 y=(m+j-kk)/2; 48 x=m-y; 49 if(x<0||y<0||x>kk||y>n-kk) 50 continue; 51 dp[i][j]+=dp[i-1][kk]*C[kk][x]%mod*C[n-kk][y]%mod; 52 if(dp[i][j]>=mod) 53 dp[i][j]%=mod; 54 } 55 printf("%lld\n",dp[k][0]); 56 } 57 return 0; 58 }