• 【HNOI2011】卡农


    题面

    题解

    将无序化为有序,最后答案除以$m!$。

    设$f[i]$表示选出了$i$个子集,并且满足所有的限制的方案数。

    因为转移困难,所以考虑容斥

    1. 限制了每个数的出现次数为偶数,所以如果前$i - 1$个子集是确定的,第$i$个的选择唯一,

      一定是前面选了奇数次的元素的集合。

      所以如果没有其他限制的情况下,选出$i$个自己的方案数为$A_{2^n-1}^{i-1}$

    2. 然后减去第$i$个集合为空的情况,方案数为$f[i-1]$

    3. 然后减去第$i$个集合与之前某个子集相同的情况。

      如果将这两个相同的集合删去,剩下的集合一定合法,方案数为$f[i-2]$。

      又第$i$个子集有$2^n-1-(i-2)$种方案,同时和第$i$个子集相同的集合的位置有$i-1$种,

      所以方案数为$f[i-2] imes(i-1) imes(2^n-1-(i-2))$

    所以转移为

    $$ f[i]=A_{2^n-1}^{i-1}-f[i-1]-(f[i-2] imes(i-1) imes(2^n-1-(i-2))) $$

    边界$f[0]=1,f[1]=0$

    真毒瘤

    代码

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<algorithm>
    #define RG register
    #define file(x) freopen(#x".in", "r", stdin);freopen(#x".out", "w", stdout);
    #define clear(x, y) memset(x, y, sizeof(x))
    
    const int maxn(1000010), Mod(100000007);
    int n, m, f[maxn], Inv, A[maxn], Pow;
    
    int fastpow(int x, int y)
    {
    	int ans = 1;
    	while(y)
    	{
    		if(y & 1) ans = 1ll * ans * x % Mod;
    		x = 1ll * x * x % Mod, y >>= 1;
    	}
    	return ans;
    }
    
    int main()
    {
    	scanf("%d%d", &n, &m);
    	f[0] = A[0] = Inv = 1;
    	for(RG int i = 2; i <= m; i++) Inv = 1ll * Inv * i % Mod;
    	Inv = fastpow(Inv, Mod - 2); Pow = (fastpow(2, n) - 1 + Mod) % Mod;
    	for(RG int i = 1; i <= m; i++) A[i] = 1ll * A[i - 1] * (Pow - i + 1) % Mod;
    	for(RG int i = 2; i <= m; i++)
    	{
    		f[i] = (A[i - 1] - f[i - 1] + Mod) % Mod;
    		f[i] = (f[i] - 1ll * f[i - 2] * (i - 1)
    				% Mod * (Pow - (i - 2)) % Mod) % Mod;
    		f[i] = (f[i] + Mod) % Mod;
    	}
    	printf("%lld
    ", 1ll * f[m] * Inv % Mod);
    	return 0;
    }
    
  • 相关阅读:
    参考资料来自 懒兔子 的公众号
    Etcd
    zookeeper 杂记
    十二五
    防火墙
    APScheduler
    docker管理工具protainer
    java学习笔记
    linux学习笔记1
    [POI2007]ZAP-Queries
  • 原文地址:https://www.cnblogs.com/cj-xxz/p/10220990.html
Copyright © 2020-2023  润新知