博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ 2839 集合计数
阅读量:5323 次
发布时间:2019-06-14

本文共 1567 字,大约阅读时间需要 5 分钟。

看计数想容斥

考虑强制选 $K$ 个数作为子集,剩下数组成的集合随便选几个子集使得它们交集为空

显然 $n$ 个数中强制选 $K$ 个数的方案数是 $C_{n}^{K}$

剩下的数构成的子集总数有 $2^{n-K}$ 个,那么如果没有交集为空的限制方案数就是 $2^{2^{n-K}}-1$(注意要 $-1$,因为空集取和不取是一样的)

那么根据乘法原理显然,交集元素个数 至少 为 $K$ 的方案数就是 $C_{n}^{K} (2^{2^{n-K}}-1) $

设 $F_{i}$ 表示交集元素个数至少为 $i$ 的方案数

根据容斥,剩下的数交集为空的方案数就是 $F_{0}-F_{1}+F_{2}-F_{3}+...+(-1)^{n-K}F_{n-K}$

把交集为空的方案数乘上强制选 $K$ 个数作为子集的方案数 $C_{n}^{K}$ 就好了

注意到算 $F_{i}$ 时要算 $2^{2^{n-i}}$ ,发现 $2^{2^{n-i}} = 2^{2^{n-i-1}} \cdot 2^{2^{n-i-1}}$

然后预处理阶乘和阶乘逆元就好了,具体看代码

#include
#include
#include
#include
#include
using namespace std;typedef long long ll;inline int read(){ int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f;}const int N=1e6+7,mo=1e9+7;int n,K,ans;ll fac[N],facinv[N],inv[N];inline ll C(int x,int y) { return fac[x]*facinv[y]%mo*facinv[x-y]%mo; }inline ll fk(ll x) { return x>=mo ? x-mo : x; }int main(){ n=read(),K=read(); fac[0]=1; facinv[0]=1; inv[1]=1; for(int i=1;i<=n;i++) { if(i!=1) inv[i]=1ll*(mo-mo/i)*inv[mo%i]%mo; fac[i]=fac[i-1]*i%mo; facinv[i]=facinv[i-1]*inv[i]%mo; } ll now=2; n-=K; for(int i=n;i>=0;i--) { if(i&1) ans=( ans - C(n,i)*(now-1)%mo +mo )%mo; else ans=fk( ans + C(n,i)*(now-1)%mo ); now=now*now%mo; } printf("%lld",ans*C(n+K,K)%mo); return 0;}

转载于:https://www.cnblogs.com/LLTYYC/p/10775427.html

你可能感兴趣的文章
SRM 628 DIV2
查看>>
2018-2019-2 20165314『网络对抗技术』Exp5:MSF基础应用
查看>>
SecureCRT的使用方法和技巧(详细使用教程)
查看>>
自建数据源(RSO2)、及数据源增强
查看>>
2018icpc徐州OnlineA Hard to prepare
查看>>
使用命令创建数据库和表
查看>>
【转】redo与undo
查看>>
安卓当中的线程和每秒刷一次
查看>>
wpf样式绑定 行为绑定 事件关联 路由事件实例
查看>>
TCL:表格(xls)中写入数据
查看>>
Oracle事务
查看>>
String类中的equals方法总结(转载)
查看>>
标识符
查看>>
一步步教你轻松学奇异值分解SVD降维算法
查看>>
内存地址对齐
查看>>
创新课程管理系统数据库设计心得
查看>>
Could not resolve view with name '***' in servlet with name 'dispatcher'
查看>>
[转载] redis 的两种持久化方式及原理
查看>>
MyBaits学习
查看>>
管道,数据共享,进程池
查看>>