解题思路:

容斥定理,考虑选出若干集合使得交集至少为k的方案数,有f(i)=Cin×(22n−i−1),可以理解为已经选定了i个,剩下2n−i

个集合,每个可以选或不选,但是不能一个也不选。但是这样做肯定会有重复的,我们思考容斥系数是什么。

当我们计算交集至少为k的时候,每个交集为j的方案都会被计算Ckj

次,所以
f(k)的系数是1
f(k+1)的系数是−Ckk+1
f(k+2)的系数−Ckk+2+Ckk+1Ck+1k+2=Ckk+2(小tips:CMNCSM=CSNCN−MN−S

以此类推,f(i)的系数就是(−1)i−kCki

所以答案为∑i=kn(−1)i−kCkiCin(22n−i−1)

求组合数需要线性筛逆元,方法:i−1≡−⌊pi⌋×(p%i)−1(modp)

求(22i−1)

可以采用从n到k枚举i的方法,初值tmp=1,然后tmp=tmp*(tmp+2)。



注意事项:

参考代码:

#include <cstdio>

#include <cstring>

#include <iostream>

using namespace std;

typedef long long ll;

const ll mod=1000000007;

ll n,k,ans;

ll ine[1000010],jcc[1000010],jc[1000010];

ll c(ll x,ll y)

{

    return jc[x]*jcc[y]%mod*jcc[x-y]%mod;

}

int main()

{

    scanf("%lld%lld",&n,&k);

    ll i,j,flag,tmp;

    ine[1]=jc[1]=jcc[1]=jc[0]=jcc[0]=1;

    for(i=2;i<=n;i++)

    {

        ine[i]=(mod-(mod/i)*ine[mod%i])%mod;

        jcc[i]=jcc[i-1]*ine[i]%mod;

        jc[i]=jc[i-1]*i%mod;

    }

    for(i=n,flag=((n-k)&1)?-1:1,tmp=1;i>=k;i--)

    {

        ans=(ans+mod+flag*c(i,k)*c(n,i)%mod*tmp%mod)%mod;

        flag=-flag,tmp=tmp*(tmp+2)%mod;

    }

    printf("%lld",ans);

    return 0;

}


点赞(2)
 

0.0分

2 人评分

C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:

一点编程也不会写的:零基础C语言学练课程

解决困扰你多年的C语言疑难杂症特性的C语言进阶课程

从零到写出一个爬虫的Python编程课程

只会语法写不出代码?手把手带你写100个编程真题的编程百练课程

信息学奥赛或C++选手的 必学C++课程

蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程

手把手讲解近五年真题的蓝桥杯辅导课程

评论列表 共有 2 条评论

Insane 2年前 回复TA
酷,但希望能把公式写清楚。
flags 3年前 回复TA
这个解释看着懵逼