• poj3718 Facer's Chocolate Dream


    题目戳这里

    这是一道好题。首先我们将模型转换一下,就两个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;
    }
    
  • 相关阅读:
    csv大文件分割以及添加表头
    菜鸟装机大杂烩
    CENTOS 基础指令——查看系统环境
    centos使用163 yum源
    MySQL my.cnf参数配置优化详解
    phpcms 实现动态价格
    phpcms模块开发中的小问题及解决方法
    关于v9缓存的那点事
    nvm-windows 手动安装 nvm use 无效 'node' 不是内部或外部命令,也不是可运行的程序
    最新eclipse国内镜像站,比ustc等站点资源新。
  • 原文地址:https://www.cnblogs.com/mmlz/p/6388438.html
Copyright © 2020-2023  润新知