题目戳这里。
这是一道好题。首先我们将模型转换一下,就两个01串异或一下,得到新串(S)。现在就是求有有多少种选法,从空集合变成(S)。其实这到题目只跟(S)中(1)的数目有关——因为所有巧克力是等价的。我们设(f[m][T])表示前(m)次操作,使得集合中有(T)个(1)的方案数。转移:
[f[a][b] = left( sum_{i=0}^3f[a-1][b+2i-3] imes inom{N-b}{i} imes inom{b}{3-i}-f[a-2][b] imes left(inom{N}{3}-a+2
ight)
ight)/a
]
我们现在来解释一下这个方程。
[sum_{i=0}^3f[a-1][b+2i-3] imes inom{N-b}{i} imes inom{b}{3-i}
]
我们枚举我们接下拿的那盘用(i)盘是从(0)变成(1),(3-i)盘是从(1)变成(0)(不管重复)。这里可能有人问为什么是(inom{N-b}{i})不是什么xxx(具体的我忘了)的。因为如果那样你就把(1)的位置也考虑进来了,这样是把(1)的位置固定了。
然后就是把重复的部分减去。我们不妨设第(a)次与(a-1)次重复了(反正是组合),我们就可以减去$$f[a-2][b] imes inom{N}{3}-a+2$$
然后这一次可以发生在前(a)次中任何一次,故最后除以个(a)(因为我们在这里强加了次序,我们把它当作了排列,实际为组合)。
#include<cstdio>
#include<cstdlib>
using namespace std;
const int maxn = 1010,rhl = 10007;
int N,M,cnt,C[maxn][maxn],f[maxn][maxn],inv[maxn]; bool A[maxn],exist[maxn][maxn];
inline int qsm(int a,int b)
{
int ret = 1;
for (;b;b >>= 1,(a *= a) %= rhl) if (b & 1) (ret *= a) %= rhl;
return ret;
}
inline void ready()
{
for (int i = 1;i <= 1000;++i) inv[i] = qsm(i,rhl-2);
C[0][0] = 1;
for (int i = 1;i <= 1000;++i)
{
C[i][0] = 1;
for (int j = 1;j <= i;++j)
{
C[i][j] = C[i-1][j-1]+C[i-1][j];
if (C[i][j] >= rhl) C[i][j] -= rhl;
}
}
}
inline int dp(int a,int b)
{
if (exist[a][b]) return f[a][b];
if (a == 0) return 0;
exist[a][b] = true;
for (int i = 0;i <= 3;++i)
{
if (N-b < i||3-i > b) continue;
f[a][b] += dp(a-1,b+2*i-3)*C[N-b][i]%rhl*C[b][3-i]%rhl;
if (f[a][b] >= rhl) f[a][b] -= rhl;
}
f[a][b] -= f[a-2][b]*(C[N][3]-a+2)%rhl;
if (f[a][b] < 0) f[a][b] += rhl;
if (f[a][b] >= rhl) f[a][b] -= rhl;
(f[a][b] *= inv[a]) %= rhl;
return f[a][b];
}
int main()
{
freopen("3718.in","r",stdin);
freopen("3718.out","w",stdout);
ready();
while (true)
{
scanf("%d %d",&N,&M); if (!N && !M) break; cnt = 0;
for (int i = 1,a;i <= N;++i) scanf("%1d",&a),A[i] = (bool)a;
for (int i = 1,a;i <= N;++i) scanf("%1d",&a),cnt += (a^(int)A[i]);
for (int i = 0;i <= M;++i) for (int j = 0;j <= N;++j) f[i][j] = exist[i][j] = 0;
f[0][0] = 1; exist[0][0] = true;
printf("%d
",dp(M,cnt));
}
fclose(stdin); fclose(stdout);
return 0;
}