zoukankan      html  css  js  c++  java
  • 容斥原理及证明

    定理

    设共有(n)个集合,(A_i)表示第(i)个集合,则所有集合的并集可表示成以下形式:

    [|A_1cup A_2cup cdotscup A_n|=sum_{i=1}^n (-1)^{i-1}sum|A_1cap A_2capcdotscap A_i| ]

    证明

    设某个元素被(x)个集合包含,显然地,其对左式的贡献为1,因为在并集中只计算一次。
    考虑其对于右式的贡献,它会在这(x)个集合的所有子集中被计算到。其贡献为:

    [sum_{i=1}^x C_x^i(-1)^{i-1}=-sum_{i=1}^x C_x^i(-1)^{i}=1-sum_{i=0}^x C_x^i(-1)^{i}=1-sum_{i=0}^x C_x^i(-1)^{i} imes1^{x-i}=1-(1-1)^x=1 ]

    由于所有元素对于左右两式的贡献均为1,综上即可证得等式成立。

    推论

    (A_i^c)表示(A_i)的补集,(S)表示全集,则:

    [|A_1^ccap A_2^ccapcdotscap A_n^c|=|S|-|A_1cup A_2cup cdotscup A_n|=|S|-sum_{i=1}^n (-1)^{i-1}sum|A_1cap A_2capcdotscap A_i| ]

    常用于解决限制条件较繁复的问题。

    相关练习

    [JSOI2015]染色问题

    题解

    [click]

    这三个限制可以逐个来解决,然后逐层相乘。
    当至少有(i)(j)列不染色的规定为某(i)(j)列不染色的时候,设(f_k)表示不用(k)种颜色的方案。
    则:

    [inom{c}{k}(c-k+1)^{(n-i)(m-j)}=sum_{t=k}^c inom{t}{k} f_t ]

    左式的意义为,选(k)个颜色不用的方案数。由于还有不涂色的选择,所以并不能保证只有那几个没有用到。假设有一种方案恰好有(t)种颜色没用到,根据这样的选择方式,它就被计算了(inom{t}{k})次。由此得出上式。
    二项式反演一下,或者从单纯的容斥角度而言,即可得到:

    [f_k=sum_{t=k}^c (-1)^{t-k}inom{t}{k}inom{c}{t}(c-t+1)^{(n-i)(m-j)} ]

    [egin{align*} sum_{k=1}^c f_k& =sum_{k=1}^c sum_{t=k}^c (-1)^{t-k}inom{t}{k}inom{c}{t}(c-t+1)^{(n-i)(m-j)}\ & =sum_{t=1}^c inom{t}{k}inom{c}{t}(c-t+1)^{(n-i)(m-j)} sum_{k=1}^t (-1)^{t-k}inom{t}{k}\ & =sum_{t=1}^c inom{t}{k}inom{c}{t}(c-t+1)^{(n-i)(m-j)} (-(-1)^t +sum_{k=0}^t (-1)^{t-k}1^k inom{t}{k})\ & =sum_{t=1}^c (-1)^{t+1}inom{c}{t}(c-t+1)^{(n-i)(m-j)}\ end{align*}]

    合法的方案数即为:

    [(c+1)^{(n-i)(m-j)}-sum_{k=1}^c f_k=sum_{k=0}^c (-1)^kinom{c}{k} (c-k+1)^{(n-i)(m-j)} ]

    这样的方案数,还是会算重,同样因为有不涂色的选择会导致超过(i)行或(j)列是完全空白的。再进行容斥,即可得到:

    [egin{align*} & sum_{i=0}^n (-1)^i inom{n}{i}sum_{j=0}^m (-1)^j inom{m}{j} sum_{k=0}^c (-1)^kinom{c}{k}(c-k+1)^{(n-i)(m-j)}\ & =sum_{i=0}^nsum_{k=0}^c (-1)^{i+k}inom{n}{i} inom{c}{k}sum_{j=0}^m inom{m}{j}(-1)^j(c-k+1)^{(n-i)(m-j)}\ & =sum_{i=0}^nsum_{k=0}^c (-1)^{i+k}inom{n}{i} inom{c}{k}sum_{j=0}^m [-1+(c-k+1)^{n-i}]^m \ end{align*}]

    如果不将后面的求和转化掉的话,复杂度是(O(n^3))。转化后对每一个(c-k+1)的幂进行预处理,即可达到(O(n^2logn))的复杂度。

    代码

    [click]
    #include <cstdio>
    #include <cctype>
    typedef long long ll;
    const int p=1e9+7;
    const int maxn=400+10;
    int fac[maxn],inv[maxn],pow[maxn*maxn];
    
    int max(int x,int y) {return x>y?x:y;}
    int read()
    {
    	int res=0;
    	char ch=getchar();
    	while(!isdigit(ch))
    		ch=getchar();
    	while(isdigit(ch))
    		res=res*10+ch-'0',ch=getchar();
    	return res;
    }
    int power(int a,int n)
    {
    	int res=1;
    	while(n)
    	{
    		if (n&1)
    			res=(ll)res*a%p;
    		a=(ll)a*a%p;
    		n>>=1;
    	}
    	return res;
    }
    void prework(int n)
    {
    	fac[0]=1;
    	for (int i=1;i<=n;i++)
    		fac[i]=(ll)fac[i-1]*i%p;
    	inv[n]=power(fac[n], p-2);
    	for (int i=n-1;i>=0;i--)
    		inv[i]=(ll)inv[i+1]*(i+1)%p;
    }
    int C(int n,int m)
    {
    	if (m>n)
    		return 0;
    	return (ll)fac[n]*inv[m]%p*inv[n-m]%p;
    }
    int main()
    {
    	int n=read(),m=read(),c=read();
    	prework(max(max(n, m), c));
    	int ans=0;
    	pow[0]=1;
    	for (int k=0;k<=c;k++)
    	{
    		for (int i=1;i<=n;i++)
    			pow[i]=(ll)pow[i-1]*(c-k+1)%p;
    		for (int i=0;i<=n;i++)
    		{
    			int mul=(ll)power(pow[n-i]-1, m)*C(n, i)%p*C(c, k)%p;
    			if ((i^k)&1)
    				ans-=mul;
    			else
    				ans+=mul;
    			if (ans<0)
    				ans+=p;
    			else if (ans>=p)
    				ans-=p;
    		}
    	}
    	printf("%d
    ",ans); 
    	return 0;
    }
    
  • 相关阅读:
    零基础学习python_异常处理(32-33课)
    零基础学习python_pickle(31课)
    零基础学习python_文件(28-30课)
    安全测试3_Web后端知识学习
    安全测试2_Web前端知识学习
    安全测试1_Web知识简介
    659 为什么说服人那么难?(一个理智的人不要总试图改变别人的世界观,应该找机会颠覆自己的世界观)
    总结18,展望19
    typescript 的安装
    MVC4.0 解决Controllers与Areas中控制器不能同名问题
  • 原文地址:https://www.cnblogs.com/hkr04/p/principle-of-inclusion-exclusion.html
Copyright © 2011-2022 走看看