给两个长n的01串s1和s2,要对s1进行k次修改,每次修改m个不同位置,问有几种方式修改成s2。
想偏了,只想到原始的01数值是不重要的,因为每个位置修改次数的奇偶性是确定的这一层。。
其实,这题只要关心从起点到终点有几个位置是不同的,一个数值足矣。
然后具体的状态就是:dp[i][j]表示,进行i次修改后有j个位置不同的方案数。
转移用我为人人,dp[i][j]通过选择修改a个位置不同、m-a个位置相同转移到dp[i+1][j-(a-(m-a))],即dp[i+1][j-(a-(m-a))]=∑C(j,a)*C(n-j,m-a)*dp[i][j]。
这题的状态的设计和转移对我来说还是挺巧的。。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 long long d[111][111],C[111][111]; 6 int main(){ 7 for(int i=0; i<111; ++i) C[i][0]=1; 8 for(int i=1; i<111; ++i){ 9 for(int j=1; j<=i; ++j) C[i][j]=(C[i-1][j-1]+C[i-1][j])%1000000009; 10 } 11 char s1[111],s2[111]; 12 int n,k,m; 13 while(~scanf("%d%d%d",&n,&k,&m)){ 14 scanf("%s%s",s1,s2); 15 int cnt=0; 16 for(int i=0; i<n; ++i){ 17 if(s1[i]!=s2[i]) ++cnt; 18 } 19 memset(d,0,sizeof(d)); 20 d[0][cnt]=1; 21 for(int i=0; i<k; ++i){ 22 for(int j=0; j<=n; ++j){ 23 if(d[i][j]==0) continue; 24 for(int k=0; k<=j; ++k){ 25 if(j-(k-(m-k))<0 || n-j<0 || m-k<0) continue; 26 d[i+1][j-(k-(m-k))]+=C[j][k]*C[n-j][m-k]%1000000009*d[i][j]%1000000009; 27 d[i+1][j-(k-(m-k))]%=1000000009; 28 } 29 } 30 } 31 printf("%lld\n",d[k][0]); 32 } 33 return 0; 34 }