题意:
给定一个01序列,有K次操作,每次可以将M个元素翻转,给定初始初始状态和终止状态,求方案数
范围&性质:$1\le n\le 100,0\le k\le 100,0\le m\le n $
分析:
由于翻转不要求顺序,所以位置对方案没有任何影响,我们自然而然可以将点分为两类:与目标状态相同,与目标状态相反
然后我们可以设计DP状态,\(f[i][j]\)表示进行了\(i\)次操作有\(j\)个元素和目标状态不一样,推导出DP方程如下:
\[f[i][j-l+k-l]=\sum_{l=0}^k f[i-1][j]\times C_j^l\times C_{n-j}^{k-l}
\]
表示第\(i\)次操作,减少了\(l\)个,增加了\(k-l\)个,最后的答案为\(f[k][0]\)
代码:
#include<bits/stdc++.h>
using namespace std;
namespace zzc
{
const long long mod= 1e9+7;
long long n,k,m,cnt=0;
long long f[105][105],c[105][105];
char a[105],b[105];
void init()
{
c[0][0]=1;
c[1][0]=c[1][1]=1;
for(int i=2;i<=100;i++)
{
c[i][0]=1;
for(int j=1;j<=i;j++)
{
c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
}
}
}
void work()
{
init();
scanf("%lld%lld%lld",&n,&k,&m);
scanf("%s",a+1);
scanf("%s",b+1);
for(long long i=1;i<=n;i++)
{
if(a[i]!=b[i])
{
cnt++;
}
}
f[0][cnt]=1;
for(long long i=1;i<=k;i++)
{
for(long long j=0;j<=n;j++)
{
for(long long l=0;l<=min(m,j);l++)
{
f[i][j-l+m-l]=(f[i][j-l+m-l]+(f[i-1][j]*c[j][l])%mod*c[n-j][m-l]%mod)%mod;
}
}
}
printf("%lld",f[k][0]);
}
}
int main()
{
zzc::work();
return 0;
}