[hdu6391 多校20180813 Lord Li's problem](组合数学+dp)

链接:http://acm.hdu.edu.cn/showproblem.php?pid=6391

题意:根据异或的性质,X_0⊕X_1⊕X_2⊕X_3⊕…..⊕X_(M-1)=S⊕T 计算出S⊕T中一共有cnt个1,将这个二进制数标准化, 使它成为前面N-cnt个0,后cnt个1的二进制数,答案保持不变,问题变为:用K个N位且有3个1的不同二进制数进行 异或,最终得到前面N-cnt个0,后面cnt个1这个二进制数,有多少种方案? 递推。设 表示用K个N位且有 3个1的不同二进制数进行异或,最终得到前面N-cnt个0,后面cnt个1这个二进制数的方案数。 递推方程: 此时得到的 未去除加入数字的先后顺序和加入重复串带来的影响 考虑加入重复串的影响, 表示去除加入i-2个数字并且后面有j个1这个二进制数但后来又异或上两 个之前没用过的相同的数的方案数, 考虑二进制数加入的先后顺序给答案带来的额外贡献, 即 ,其中 为数字i关于模mod的逆元

代码:

#pragma warning(disable:4996)
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int mod =19260817;
bool flag = 0;
const int maxn = 45 + 6;
const int Maxn = 1e6 + 6;
char a[maxn], b[maxn];
ll dp[maxn][maxn];
int n, k;
int C[maxn][maxn];

ll qpow(ll a, ll b) {
	ll res = 1;
	while (b) {
		if (b & 1)
			res = res * a%mod;
		a = a * a%mod;
		b >>= 1;
	}
	return res;
}

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]) % mod;
		}
	}
}

ll solve() {
	int res = 0;
	for (int i = 0; i< n; i++) {
		res += (a[i] != b[i]);
	}
	return res;
}

int main() {
	int ca = 0;
	init();
	while (~scanf("%d%d", &n, &k), (n + k)) {
		scanf("%s%s", a,b);
		int cnt =solve();
		dp[0][0] = 1;
		ll fac = 1;
		for (int i = 1; i <= k; i++) {
			fac = fac * i%mod;
			for (int j = 0; j <= n; j++) {
				dp[i][j] = 0;
				if(j>=3)dp[i][j] += dp[i - 1][j - 3] * C[n-(j-3)][3];
				if(j>=1)dp[i][j] += dp[i - 1][j - 1] * C[n - (j - 1)][2] %mod* (j - 1);
				if(j+1<=n)dp[i][j] += dp[i - 1][j + 1] * C[n - (j + 1)][1] %mod* C[j + 1][2];
				if(j+3<=n)dp[i][j] += dp[i - 1][j + 3] * C[j + 3][3];
				if(i>=2)dp[i][j] -= dp[i - 2][j] * (i - 1)%mod*(C[n][3] - (i - 2));
				dp[i][j] %= mod;
			}
		}
		ll ans = dp[k][cnt];
		ans=ans*qpow(fac, mod - 2) % mod*qpow(C[n][cnt], mod - 2) % mod;
		printf("Case #%d: %lld\n", ++ca, (ans+mod)%mod);
	}
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值