(上不了p站我要死了,侵权度娘背锅)

Description

一个有N个元素的集合有2^N个不同子集(包含空集),现在要在这2^N个集合中取出若干集合(至少一个),使得

它们的交集的元素个数为K,求取法的方案数,答案模1000000007。(是质数喔~)

Input

一行两个整数N,K

Output

一行为答案。

Sample Input

3 2

Sample Output

6

HINT

【样例说明】

假设原集合为{A,B,C}

则满足条件的方案为:{AB,ABC},{AC,ABC},{BC,ABC},{AB},{AC},{BC}

【数据说明】

对于100%的数据,1≤N≤1000000;0≤K≤N;

自己的数论果然还是太差了,看来大佬的博客才知道该怎么做

当 题目所求难以直接求得,而扩大一些的范围方便求 时,就思考用容斥定理。对于这道题,交集恰好为k的不好求,但是交集元素包含k的方便求,所以就考虑用 包含k的方案数-包含k+1的方案数+包含k+2的方案数…… 来求出 恰好包含k 的方案数。于是就将大问题拆成了相似的小问题。

交集元素个数包含i的方案数是很好求的。首先要保证一定有i个元素,所以就是“从n个元素中选i个元素”,即C(n,i)。接下来就是选择一些集合包含选出来的i个元素的方案数,该问题等价于选一些集合不包含这i个元素的方案数。即 除开这i个元素,剩下的n-i个元素组成的集合有2^(n-i)个,每个集合有选与不选两种状态,所以就是2^(2^(n-i))-1种方案。因为不能全都不选(2^(n-i)个集合中已包含空集),所以要-1。

但是却发现这样的做法连样例都过不了O^O,难道说这个方法错了吗?冷静下来仔细分析样例,按照这样的算法得出:

交集包含2个的:共9种

{{1,2}},{{1,2,3}},{{1,2},{1,2,3}}

{{1,3}},{{1,3,2}},{{1,3},{1,3,2}}

{{3,2}},{{3,2,1}},{{3,2},{3,2,1}}

交集包含3个的:共1种

{{1,2,3}}

我们发现,在“交集包含2的”的情况中,集合{1,2,3}出现了3次,包含的2个元素分别是我们选出来的{1,2},{2,3},{1,3}。所以我们算重了3次。化为一般情况就是 包含i个的 方案∗选择包含的是哪k个元素(i个元素中选k个元素),即为 C(i,k)∗C(n,i)∗(2^(2^(n-i)-1)。

加上容斥原理,令f[i]=2^(2^(n-i)-1,最终的公式为:

然后有一些缩短时间的小技巧。虽然题目的数据o(nlogn)是能过的,但是相比起来就太慢了一些,n再加一个0就完了。

而logn的复杂度主要是出在 阶乘求逆元 和 求f[i] 上。仔细观察性质,发现f[i]虽然是一个指数套指数的形式,但由于底数是2,所以可以相乘来递推(这样也就不用担心指数的快速幂的模数要取phi(mod)了)。而 阶乘的逆元是可以线性求解的(我以前一直都不知道qwq,又长见识了)。

因为 ( (n-1)! )^-1 = (n!)^-1 * n ,所以先求出阶乘,o(logn)求出 n! 的逆元,再倒着推回去。在本题总时间减少了近一半。

AC代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
#ifdef WIN32
#define RIN "%I64d"
#else
#define RIN "%lld"
#endif template <typename T>inline void read(T &res){
T k=1,x=0;char ch=0;
while(ch<'0'||ch>'9'){if(ch=='-')k=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
res=k*x;
} const int N=1000000+5;
const ll MOD=1e9+7; ll n,k,jiec[N],niy[N];
ll f[N]; void exgcd(ll a,ll b,ll &x,ll &y){
if(b==0){
x=1,y=0;
return;
}
ll x0,y0;
exgcd(b,a%b,x0,y0);
x=y0;
y=x0-(a/b)*y0;
}
ll inverse(ll a){
ll x,y;
exgcd(a,MOD,x,y);
return (x%MOD+MOD)%MOD;
}
void init(){
jiec[0]=niy[0]=1;
/*for(int i=1;i<=n;i++){
jiec[i]=jiec[i-1]*i%MOD;
niy[i]=inverse(jiec[i]);
}*/
for(int i=1;i<=n;i++) jiec[i]=jiec[i-1]*i%MOD;
niy[n]=inverse(jiec[n]);
for(int i=n-1;i>=1;i--) niy[i]=niy[i+1]*(i+1)%MOD;
}
ll power(ll a,ll b,ll mod){
ll rt=1;
for(int i=b;i;i>>=1,a=(a*a)%mod)
if(i&1) rt=(rt*a)%mod;
return rt;
}
ll F(ll x){
/*ll tmp=power(2,x,MOD-1);
return (power(2,tmp,MOD)-1+MOD)%MOD;*/
return (f[x]-1+MOD)%MOD;
}
ll C(ll a,ll b){
if(b>a) return 0;
return jiec[a]*niy[b]%MOD*niy[a-b]%MOD;
}
int main(){
read(n),read(k);
init();
f[0]=2;
for(int i=1;i<=n-k;i++) f[i]=f[i-1]*f[i-1]%MOD;
ll ans=0;
for(ll i=k;i<=n;i++)
ans=(ans+C(n,i)*C(i,k)%MOD*F(n-i)%MOD*((i-k&1)?-1:1)%MOD+MOD)%MOD;
cout<<ans<<endl;
return 0;
}

【bzoj2839】【集合计数】容斥原理+线性求阶乘逆元小技巧的更多相关文章

  1. 【BZOJ-2839】集合计数 容斥原理 + 线性推逆元 + 排列组合

    2839: 集合计数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 229  Solved: 120[Submit][Status][Discuss] ...

  2. bzoj4591 [Shoi2015]超能粒子炮·改——组合数学(+求阶乘逆元新姿势)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4591 这题不是很裸啊(所以我就不会了) 得稍微推导一下,看这个博客好了:https://bl ...

  3. bzoj2839 集合计数 组合计数 容斥原理|题解

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

  4. bzoj2839 集合计数(容斥)

    2839: 集合计数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 883  Solved: 490[Submit][Status][Discuss] ...

  5. bzoj2839 集合计数(容斥+组合)

    集合计数 内存限制:128 MiB 时间限制:1000 ms 标准输入输出     题目描述 一个有N个元素的集合有2^N个不同子集(包含空集),现在要在这2^N个集合中取出若干集合(至少一个),使得 ...

  6. BZOJ 2839: 集合计数 [容斥原理 组合]

    2839: 集合计数 题意:n个元素的集合,选出若干子集使得交集大小为k,求方案数 先选出k个\(\binom{n}{k}\),剩下选出一些集合交集为空集 考虑容斥 \[ 交集为\emptyset = ...

  7. bzoj2839: 集合计数 容斥+组合

    2839: 集合计数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 523  Solved: 287[Submit][Status][Discuss] ...

  8. bzoj2839 集合计数

    F.A.Qs Home Discuss ProblemSet Status Ranklist Contest 入门OJ ModifyUser  Logout 捐赠本站 2839: 集合计数 Time ...

  9. 2019.02.09 bzoj2839: 集合计数(容斥原理)

    传送门 题意简述:对于一个有N个元素的集合在其2^N个子集中取出若干集合(至少一个),使得它们的交集的元素个数为K,求取法的方案数. 思路:考虑枚举相交的是哪kkk个,有CnkC_n^kCnk​种方案 ...

随机推荐

  1. 【志银】Win764位配置Github环境及将代码部署到Github pages-志银强势总结

    (软件及教程下载分享:链接:http://pan.baidu.com/s/1dFysay9 密码:pug0) 1-安装Git-2.9.2-64-bit.exe(解压安装文件,运行安装程序,除了记得修改 ...

  2. 团队项目-第三次scrum 会议

    时间:10.25 时长:30分钟 地点:线上 工作情况 团队成员 已完成任务 待完成任务 解小锐 根据初步讨论结果编写初步的api文档 编写project和projectGenerator类 陈鑫 采 ...

  3. iOS runLoop 理解

    目录 概述 run loop modes 一.概述 run loop叫事件处理循环,就是循环地接受各种各样的事件.run loop是oc用来管理线程里异步事件的工具.一个线程通过run loop可以监 ...

  4. 【Luogu】P3228数列(数学题)

    题目链接 考虑我们把所有的增加量拿出来做成一个序列b. 那么在所有n中开头中$1~\sum\limits_{i=1}^{k-1}b[i]$是合法的 也就是说我们枚举所有b[i],然后答案就是$n*m^ ...

  5. 【BestCoder 1st Anniversary】

    AB题都是签到题.... C 题意: 有一串数列,An=3*n*(n-1)+1 然后要从A数列中选取尽量少个数(可重复),使得Sum(An)=m 题解: 贪心地想,能拿大就拿大很明显就是错的...[哪 ...

  6. [poj] 1235 Farm Tour || 最小费用最大流

    原题 费用流板子题. 费用流与最大流的区别就是把bfs改为spfa,dfs时把按deep搜索改成按最短路搜索即可 #include<cstdio> #include<queue> ...

  7. 中英文混截,一个中文相当于n个英文

    项目中遇到这么个需求,截取中英文字符串,一个中文相当于2个英文,全英文时截取12个英文字母,全中文时是6个中文汉字,中英文混合时是12个字节,在网上有找到这样的解决方案,但我没能静下心来研究懂,于是自 ...

  8. 如何用cookie保存用户的登录的密码和用户名

    思路:绘制一个简单的登录界面的Servlet并要在此页面中读取保存密码和用户名的cookie--->在登录处理界面的servlet中把用户名和密码保存到cookie中 //登录界面的Servle ...

  9. css去掉点击连接时所产生的虚线边框技巧兼容符合w3c标准的浏览器

    解决方法: 1.在css中加上outline:none; 代码如下: a.fontnav { text-align:left;color:#555; text-decoration:none; out ...

  10. OwnCloud 搭建

    owncloud 的安装方式可以在 [ 官网 ] 找到. 本文会说明 owncloud 在 CentOS 7.x 上基于 LAMP 安装, 以及简单的用 docker 镜像启动的例子. 基于 LAMP ...