ZOJ3791_An Easy Game

给出两个等长的字符串,每次需要改变m个数字,每次必须改变k个数字,求从第一个串变化到第二个串的方案数。

DP。f[i][j]改变i步后,有j个位置被改变的方案数。然后直接枚举当前改变的几个位置是前面重合的。

然后统计答案输出即可。

 

 

#include <iostream>
#include <cstring>
#include <cstdio>
#define M 1000000009
#define maxn 105
typedef long long ll;
using namespace std;

ll C[maxn][maxn];
ll f[maxn][maxn];
int n,k,m,change;
ll ans;

ll power(ll A,ll B)
{
    ll tot=1;
    while (B){
        if (B&1) tot=tot*A%M;
        A=A*A%M,B>>=1;
    }
    return tot;
}

void _init()
{
    memset(C,0,sizeof C);
    C[0][0]=1;
    for (int i=1; i<maxn; i++){
        C[i][0]=1;
        for (int j=1; j<=i; j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%M;
    }
}

int main()
{
    _init();
    char s1[maxn],s2[maxn];
    while (scanf("%d%d%d",&n,&k,&m)!=EOF){
        change=0;
        scanf("%s%s",s1,s2);
        for (int i=0; i<n; i++)
            if (s1[i]!=s2[i]) change++;
        memset(f,0,sizeof f);
        f[0][0]=1;
        for (int i=0; i<k; i++)//after the ith time of changes
            for (int j=0; j<=n; j++){//the number of 1 is j
                if (f[i][j]==0) continue;
                for (int x=max(0,j+m-n); x<=min(j,m); x++){
                    f[i+1][j-x+m-x]+=f[i][j]*(C[j][x]*C[n-j][m-x]%M)%M;
                    f[i+1][j-x+m-x]%=M;
                }
            }
        ans=f[k][change]*power(C[n][change],M-2)%M;
        printf("%d
",(int)ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/lochan/p/3888707.html