luogu-P10596题解

简要题意

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

数据范围:1KN106

题解

我们设 f(i) 表示选出子集大小恰好为 i 的方案数,然而我们发现这个东西不好转移。但是,如果我们先求出一个限制条件少一点但是比较好求的东西 g(i) 再去求 f(i) 就会简单许多(也许。

于是就有 g(i) 表示钦定 i 个元素在交集中(其他元素不考虑),这样 g(i) 就比较好求了,我们可以把 g(i) 的式子写出来:g(i)=(ni)(22ni1)。为什么呢?首先我们需要从 n 个元素中选择 i 个元素,所以有 (ni),然后对于剩下 ni 个元素,我们可以列举出可能存在的集合的可能,也就是 2ni 种可能,对于这些集合我们可以选可以不选,但是题目要求至少选一个,所以就是一个 2ni 元集去掉空集,然后选的元素与不选的元素之间互有影响所以是乘法原理。

然后就是去找 fg 的关系了。其实对于 g,我们还有另一种求法:g(i)=j=in(ji)f(j)。其实就是对于选出子集大小恰为 j 的方案中再去选出 i 个,与第一种方法等价。

然后看到后面这坨直接二项式反演就可以得到:

f(i)=j=in(1)ji(ji)(nj)(22nj1)

然后直接算就行。

代码

signed main(){
    n = rd(), k = rd();
    fac[0] = bs[0] = 1;
    for(int i = 1; i <= n; ++i)fac[i] = fac[i - 1] * i % mod, bs[i] = bs[i - 1] * 2 % (mod - 1);
    inv[n] = qmi(fac[n], mod - 2);
    for(int i = n - 1; i; --i)inv[i] = inv[i + 1] * (i + 1) % mod;
    for(int i = k; i <= n; ++i){
        ll op = qmi(- 1, i - k);
        ll t1 = C(i, k), t2 = C(n, i);
        ll tt = (qmi(2, bs[n - i]) - 1 + mod) % mod;
        (ans += op * t1 % mod * t2 % mod * tt % mod + mod) %= mod;
    }
    cout << ans;
    return 0;
}
posted @   Lyrella  阅读(27)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示