集合计数

我想的容斥和题解不太一样

我也是想先在n个里确定K个

然后设 $$f_i=C_n^i*\sum_{p=0}^{n-i} $$

$$ ans=f_K-f_{K+1}+f_{K+2}... $$

然而这个并不对,3 2 的样例 算$f_k$的时候就已经是6了

正解:

$$ ans=C_n^K*( C_{n-K}^0*2^{2^{n-K}}-C_{n-K}^1*2^{2^{n-K-1}}... ) $$

解释:

先枚举确定n个里面的K个

在枚举另外 n-K 个元素里有几个是在交集里被选上了

$2^{2^{i}}$意思是 有i个元素剩余,子集有$2^i$个,在这些子集里再选

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=1000006;
const int mod=1000000007;

int ou(int x)
{
    int tt=x,q1=sqrt(x);
    for(int i=2;i<=q1;++i)
        if(x%i==0)
        {
            tt=tt-tt/i;
            while(x%i==0)
                x/=i;
        }
    if(x!=1)
        tt=tt-tt/x;
    return tt;
}

ll qpow(ll a,int ci,int mm)
{
    ll ans=1;
    while(ci)
    {
        if(ci&1)
            ans=ans*a%mm;
        a=a*a%mm;
        ci>>=1;
    }
    return ans;
}

int n,K;
ll mi[N],mi2[N];
ll jie[N],jieni[N];

void chu()
{
    int mod2=ou(mod);
    mi[0]=1;
    for(int i=1;i<=n;++i)
      mi[i]=mi[i-1]*2%mod2;
    for(int i=0;i<=n;++i)
      mi2[i]=qpow(2,mi[i],mod);
    
    jie[0]=1;
    for(int i=1;i<N;++i)
      jie[i]=jie[i-1]*i%mod;
    jieni[N-1]=qpow(jie[N-1],mod-2,mod)%mod;
    for(int i=N-2;i>=1;--i)
      jieni[i]=jieni[i+1]*(i+1)%mod;
    jieni[0]=1;
}

ll C(int n,int m)
{
    if( n<0||m<0||n<m )
        return 0;
    return jie[n]*jieni[m]%mod*jieni[n-m]%mod;
}

ll work()
{
    ll ans=0,tt;
    int q1=n-K;
    for(int i=0;i<=q1;++i)
    {
        tt=C(n-K,i)*mi2[n-K-i]%mod;
        //printf("i=%d tt=%lld\n",i,tt);
        if(i&1)
            ans=(ans-tt+mod)%mod;
        else
          ans=(ans+tt)%mod;
    }
    return ans*C(n,K)%mod;
}

int main(){
    
    scanf("%d%d",&n,&K);
    chu();
    cout<<work();
}
AA

 

posted @ 2017-10-16 07:55  A_LEAF  阅读(349)  评论(0编辑  收藏  举报