bzoj2839 集合计数(容斥+组合)
集合计数
题目描述
一个有N个元素的集合有2^N个不同子集(包含空集),现在要在这2^N个集合中取出若干集合(至少一个),使得它们的交集的元素个数为K,求取法的方案数,答案模1000000007。(是质数喔~)
输入格式
一行两个整数N,K
输出格式
一行为答案。
样例
样例输入
3 2
样例输出
6
数据范围与提示
样例说明
假设原集合为{A,B,C}
则满足条件的方案为:{AB,ABC},{AC,ABC},{BC,ABC},{AB},{AC},{BC}
数据说明
对于100%的数据,1≤N≤1000000;0≤K≤N;
一道很好的数论题(反正我看题解才做出来的 %%%%*ZJ https://www.cnblogs.com/zj75211/p/8029343.html) 我有点菜,各种错误。
思路很奇妙,第一步:首先选出来C(n,k)个数,第二步:然后我们要做的就是让剩余集合交集为空。注意,我们选的剩余集合是除了C以外还选了什么(C上再加这个集合)
解释一下
例如 3 1
假设我们通过第一步选出来的数为A
而第二步我们选出来 C,B
那么我们最终选的集合为AB ,AC
再比如我们第二步选 空集,C
那么我们最终选出来的集合为 A,AC
既然如此我们需要求的就是所有满足的情况
正确性验证被我鸽了。。。。。。
然后我们要做的就是求出方案
设f[i]为当前集合至少选出i个数的方案数
设m为n-i(即剩余个数)
对于剩余n-i个数可以构成$2^{(n-i)}$个集合
而对于这些集合每个都可以进行选或不选(即$2{^{2^{(n-i)}}}$)种情况
而不能都不选(对于选了空集也是一种)
则
$f[i]=C(n,i)*(2{^{2^{n-i}}}-1)$
显然我们算多了,然后我们需要容斥掉容斥系数,首先我们发现在所有f[k+1]中我们都多算了C(k+1,k)次
例如我们固定了四个数ABCD
我们在k+1中每种都多算了一次
ABC D==ACD B==ABD C==BCD A
得到对于f[k+1]:-C(k+1,k)
同理f[k+2]:+C(k+2,k+1)*C(k+1,k)==C(k+2,k)
依次类推
得到
- for(ll i=k;i<=n;i++)
- ans=(C(i,k)*f[i]%p*((i-k)&1?-1:1)+ans)%p;
实际上就类似于多项容斥
而且这题因为N<=1000000
如果算C现算肯定不行,考虑到用多次,打表(阶乘及阶乘逆元),但求逆元带log仍然超时
所以还要线性求逆元
- ni[n]=meng(jie[n],p-2);
- for(ll i=n-1;i>=1;i--)ni[i]=ni[i+1]*(i+1)%p;
理解一下逆元实际上就是1/?
而$1/(n+1)!*(n+1)$其实就是$1/(n)! $就求出来逆元了
两个注意点
:for(ll i=1;i<=maxn;i++) ermi[i]=2*ermi[i-1]%(p-1);//2^ermi[i]%p!=2^ermi[i]%p调两节课
:for(ll i=0;i<=n;i++)又一节半课,实在是菜
:ermi[0]又二十分钟,
除了第一个是稍微有一点思维的错,别的都是低错。实不应该
首先关于为什么mod (p-1)而不是mod (p)
这其实要推出来,首先我们必须知道${2^{2^i mod p}}{!=2^{2^i}{mod p}}$
怎么办 设${2^i}==(kφ(p)+t)$,则原式就为$(2^{k*φ(p)}*2^t) {mod p}$
根据欧拉定理
$2^{φ(p)} mod p$同余于1,${2^i}==kφ(p)+t$t就等于$2^i mod φ(p)$,又φ(质数)==p-1
故%(p-1)而非%p
以下依然是本人丑陋的还带着调试的代码
- 1 #include<bits/stdc++.h>
- 2 #define ll long long
- 3 #define A 1100000
- 4 #define maxn 1000010
- 5 #define p 1000000007
- 6 using namespace std;
- 7 ll m,n,k,f[A],jie[A],ermi[A],ans,ni[A];
- 8 inline ll read()
- 9 {
- 10 ll f=1,x=0;char c=getchar();
- 11 while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
- 12 while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
- 13 return f*x;
- 14 }
- 15 ll meng(ll x,ll k)
- 16 {
- 17 ll ans=1;
- 18 for(;k;k>>=1,x=x*x%p)
- 19 if(k&1)
- 20 ans=x%p*ans%p;
- 21 return ans;
- 22 }
- 23 ll C(ll n,ll m)
- 24 {
- 25 if(m==0) return 1;
- 26 if(m>n) return 0;
- 27 else return (jie[n]*ni[m]%p*ni[n-m])%p;
- 28 }
- 29 void init()
- 30 {
- 31 n=read(),k=read();
- 32 m=n-k;
- 33 jie[0]=1;ni[0]=1;ermi[0]=1;
- 34 for(ll i=1;i<=maxn;i++) ermi[i]=2*ermi[i-1]%(p-1);//2^ermi[i]%p!=2^ermi[i]%p
- 35 for(ll i=1;i<=n;i++) jie[i]=jie[i-1]*i%p;
- 36 ni[n]=meng(jie[n],p-2);
- 37 for(ll i=n-1;i>=1;i--)ni[i]=ni[i+1]*(i+1)%p;
- 38 for(ll i=0;i<=n;i++) f[i]=C(n,i)%p*(meng(2,ermi[n-i])%p-1)%p;
- 39 }
- 40 int main()
- 41 {
- 42 // freopen("test.in","r",stdin);freopen("vio.out","w",stdout);
- 43 ans=0;
- 44 init();
- 45 for(ll i=k;i<=n;i++)
- 46 ans=(C(i,k)*f[i]%p*((i-k)&1?-1:1)+ans)%p;
- 47 cout<<(ans%p+p)%p<<endl;
- 48 }
以及对拍
- 1 #include<bits/stdc++.h>
- 2 int main()
- 3 {
- 4 while(true)
- 5 {
- 6 system("./mkd"),puts("mkd runs out");
- 7 system("./std"),puts("std runs out");
- 8 system("./vio"),puts("vio runs out");
- 9 if(system("diff std.out vio.out")) while(true);
- 10 puts("");
- 11 }
- 12 return 0;
- 13 }
嗯,完了
bzoj2839 集合计数(容斥+组合)的更多相关文章
- bzoj2839: 集合计数 容斥+组合
2839: 集合计数 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 523 Solved: 287[Submit][Status][Discuss] ...
- BZOJ2839:集合计数(容斥,组合数学)
Description 一个有N个元素的集合有2^N个不同子集(包含空集),现在要在这2^N个集合中取出若干集合(至少一个),使得它们的交集的元素个数为K,求取法的方案数,答案模1000000007. ...
- BZOJ2839 集合计数 容斥
题目描述(权限题qwq) 一个有N个元素的集合有2^N个不同子集(包含空集),现在要在这2^N个集合中取出若干集合(至少一个),使得 它们的交集的元素个数为K,求取法的方案数,答案模100000000 ...
- bzoj 2839 集合计数 容斥\广义容斥
LINK:集合计数 容斥简单题 却引出我对广义容斥的深思. 一直以来我都不理解广义容斥是为什么 在什么情况下使用. 给一张图: 这张图想要表达的意思就是这道题目的意思 而求的东西也和题目一致. 特点: ...
- BZOJ 3294: [Cqoi2011]放棋子 计数 + 容斥 + 组合
比较头疼的计数题. 我们发现,放置一个棋子会使得该棋子所在的1个行和1个列都只能放同种棋子. 定义状态 $f_{i,j,k}$ 表示目前已使用了 $i$ 个行,$j$ 个列,并放置了前 $k$ 种棋子 ...
- bzoj2839 集合计数(容斥)
2839: 集合计数 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 883 Solved: 490[Submit][Status][Discuss] ...
- [BZOJ2839]:集合计数(组合数学+容斥)
题目传送门 题目描述 .(是质数喔~) 输入格式 一行两个整数N,K. 输出格式 一行为答案. 样例 样例输入: 3 2 样例输出: 样例说明 假设原集合为{A,B,C} 则满足条件的方案为:{AB, ...
- BZOJ2839 : 集合计数 (广义容斥定理)
题目 一个有 \(N\) 个 元素的集合有 \(2^N\) 个不同子集(包含空集), 现在要在这 \(2^N\) 个集合中取出若干集合(至少一个), 使得它们的交集的元素个数为 \(K\) ,求取法的 ...
- bzoj2839 集合计数 组合计数 容斥原理|题解
集合计数 题目描述 一个有N个元素的集合有2^N个不同子集(包含空集),现在要在这2^N个集合中取出若干集合(至少一个),使得它们的交集的元素个数为K,求取法的方案数,答案模1000000007.(是 ...
随机推荐
- 如何实现一个 System Services?
<Android 系统开发做什么?>写到 Android System Services 是专注于特定功能的模块化组件,应用框架 API 所提供的功能可与系统服务通信,以访问底层硬件.An ...
- java面试一日一题:java中垃圾回收算法有哪些
问题:请讲下在java中有哪些垃圾回收算法 分析:该问题主要考察对java中垃圾回收的算法以及使用场景 回答要点: 主要从以下几点去考虑, 1.GC回收算法有哪些 2.每种算法的使用场景 3.基于垃圾 ...
- [bug] CDH 安装 Error : No matching Packages to list
信息 分析 我的系统是CentOS 7,而 cm 安装包是配合 redhat 6 的,应该选择 redhat 7 目录下的包 参考 https://community.cloudera.com/t5/ ...
- [DB] SQL 必知必会
整体架构 数据类型 文本类:CHAR.VARCHAR(可变长度字符,多使用).TEXT.LONGTEXT(文本较大时使用) 数字类:TINYINT.INT.BIGINT.FLOAT.DOUBLE 日期 ...
- Linux创建RAID概述
Linux创建RAID RAID概述 RAID(Redundant Array of Independent Disk)虚拟存储系统 RAID即独立冗余磁盘阵列,其思想是将多块独立的磁盘按不同的方式组 ...
- LTP--linux稳定性测试 linux性能测试 ltp压力测试 ltp-pan
LTP--linux稳定性测试 linux性能测试 ltp压力测试 zhangzj1030关注14人评论33710人阅读2011-12-09 12:07:45 说明:在写这篇文章之前,本人也不曾了 ...
- 什么是FOC
https://zhidao.baidu.com/question/354536332.html FOC简述 磁场定向控制系统(FOC)又称为矢量控制系统,他是选择电机某一旋转磁场轴作为特定的同步旋转 ...
- Redis SWAPDB 命令背后做了什么
Redis SWAPDB 命令背后做了什么 目录 Redis SWAPDB 命令背后做了什么 0x00 摘要 0x01 SWAPDB 基础 1.1 命令说明 1.2 演示 0x02 预先校验 0x03 ...
- java 计算下面级数之和 1/3+3/5+5/7+...+97/99
代码实例图:package judgment;/** * 计算下面级数之和 * 1/3+3/5+5/7+...+97/99; */public class Judgment { public stat ...
- 在react中使用redux并实现计数器案例
React + Redux 在recat中不使用redux 时遇到的问题 在react中组件通信的数据是单向的,顶层组件可以通过props属性向下层组件传递数据,而下层组件不能向上层组件传递数据,要实 ...