P2182 翻硬幣 DP
阿新 • • 發佈:2020-09-11
題意:
給定一個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\)
程式碼:
#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; }