集合计数(容斥原理)

题面

一个有N个元素的集合有2^N个不同子集(包含空集),现在要在这2^N个集合中取出若干集合(至少一个),使得它们的交集的元素个数为K,求取法的方案数,答案模1000000007。(是质数喔~)

思路

很容易想到先固定k个元素做交集,剩下n-k进行挑选,这个集合的所有子集2n-k个表示包含这k个元素的集合有这些个。我们再从这些集合中选若干个取交集,删去空集,方案有2^(2^(n-k))-1。

不难发现肯定是加多了的,于是按以上方法减k+1,结果又多减了,再加回来k+2……所以,这不就是容斥嘛

容斥原理

单步容斥

有的时候合法的方案数不好求,我们可以反向操作一波,用方案全集减掉不合法的方案数,就是答案

NOI2010 能量采集

给定n和m,求Σ(1<=i<=n)Σ(1<=j<=m)(GCD(i,j)*2-1)   n,m<=10W 

令f[x]表示gcd(i,j)=x的数对(i,j)的数量,这个不是很好求

令g[x]表示x是gcd(i,j)的约数的数对(i,j)的数量,那么g[x]=(n/x)*(m/x)

考虑,如果x是gcd(i,j)的约数,但gcd(i,j)却不等于x,那么gcd(i,j)可能等于什么? 2x,3x,4x,... m 所以有f[x]=g[x]-f[2x]-f[3x]-f[4x]...在1~n的范围内枚举一个数再枚举他的倍数是O(nlogn)的

多步容斥

有时候剪掉不合法方案的时候会顺便减掉一些合法方案;将这些合法方案加回去,又会加回去一些不合法方案;反反复复,就是多步容斥。

比如说我们最熟悉的这个式子

有兴趣见百度证明

容斥更多是一种思想,而并非算法,但也是有一些套路的

 

话说回来

我们给出式子 ans+=(-1)^(i-k)*C(n,i)*(2^(2^(n-i))-1)*C(i,k);

各项的意义基本已在上面说过,最后的疑惑是C(i,k)。我们多加了几个k+1呢?我们挑选的这i个里,其实每个k都有多加,也就是C(i,k)——此项的系数,不太好懂,感性理解一下,找找规律。

另外,2^(2^(n-i))中,2^(n-i)为幂数,可不能直接模。这时候就用到费马小定理。让2^(n-i)%(mod-1)

幂数取模费小证明

xy%mod=x^(y%(mod-1))*x^(y-y%(mod-1))%mod=x^(y%(mod-1))*x^(y/(mod-1)*(mod-1))%mod

      =x^(y%(mod-1))*(x^(mod-1))^(y/(mod-1))%mod;

由费马小定理得x^(mod-1)%mod=1,所以(x^(mod-1))^(y/(mod-1))%mod=1

所以xy%mod=x^(y%(mod-1))%mod;

证毕

代码

复制代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int MAX=1000010;
const ll mod=1000000007;
ll f[MAX],inv[MAX],n,k,ans;
ll power(ll a,ll k,ll pr){
    ll m=1;
    while(k){
        if(k&1)  m=m*a%pr;
        a=a*a%pr;k>>=1;
    }return m;//函数一定要有返回值 
}
ll C(int n,int m){
    if(n<m)  return 0;
    return f[n]*inv[m]%mod*inv[n-m]%mod;
}
int main(){
    scanf("%d%d",&n,&k);f[0]=1;
    for(int i=1;i<=n;++i)  f[i]=f[i-1]*i%mod;
    inv[n]=power(f[n],mod-2,mod);
    for(int i=n-1;i>=0;--i)  inv[i]=inv[i+1]*(i+1)%mod;
    int p=1;
    for(int i=k;i<=n;++i){
        ll fd=power(2,power(2,n-i,mod-1),mod)-1;
        ans=(ans+(mod+1ll*p*C(i,k)%mod*fd%mod*C(n,i)%mod)%mod)%mod;
        p=-p;//式子的符号很多,看清不要打成别的 
    }cout<<ans;
}
复制代码

 

posted @   yisiwunian  阅读(245)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示