集合计数

内存限制:128 MiB 时间限制:1000 ms 标准输入输出
 
 

题目描述

一个有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 集合计数(容斥+组合)的更多相关文章

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

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

  2. BZOJ2839:集合计数(容斥,组合数学)

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

  3. BZOJ2839 集合计数 容斥

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

  4. bzoj 2839 集合计数 容斥\广义容斥

    LINK:集合计数 容斥简单题 却引出我对广义容斥的深思. 一直以来我都不理解广义容斥是为什么 在什么情况下使用. 给一张图: 这张图想要表达的意思就是这道题目的意思 而求的东西也和题目一致. 特点: ...

  5. BZOJ 3294: [Cqoi2011]放棋子 计数 + 容斥 + 组合

    比较头疼的计数题. 我们发现,放置一个棋子会使得该棋子所在的1个行和1个列都只能放同种棋子. 定义状态 $f_{i,j,k}$ 表示目前已使用了 $i$ 个行,$j$ 个列,并放置了前 $k$ 种棋子 ...

  6. bzoj2839 集合计数(容斥)

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

  7. [BZOJ2839]:集合计数(组合数学+容斥)

    题目传送门 题目描述 .(是质数喔~) 输入格式 一行两个整数N,K. 输出格式 一行为答案. 样例 样例输入: 3 2 样例输出: 样例说明 假设原集合为{A,B,C} 则满足条件的方案为:{AB, ...

  8. BZOJ2839 : 集合计数 (广义容斥定理)

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

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

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

随机推荐

  1. HashMap底层原理分析

    本文将从以下方面结合源码进行分析:自动扩容.初始化与懒加载.哈希计算.位运算(默认采用JDK1.8).   自动扩容 扩容操作发生在putVal最后部分,在增加元素后才判断是否需要扩容,如果超过阈值, ...

  2. 关于Java处理串口二进制数据的问题 byte的范围 一个字节8bits

    前置知识点 byte的范围[-128~127] 内存里表现为 0x00~0xFF 刚好是一个8bits的字节 问题 byte[] hexData = new byte[] {0x01, 0x03, 0 ...

  3. JavaScript中DOM与BOM的区别

    1.BOM BOM全称为Brower Object Model,中文翻译为浏览器对象模型,提供了独立于内容而与浏览器窗口进行交互的对象.描述了与浏览器进行交互的方法和接口.通过BOM可以用来获取或设置 ...

  4. 集成Spring Data JPA

    1.Spring Data JPA简介 Spring Data是一个用于简化数据访问,并支持云服务的开源框 使用完成Spring Data JPA对user表的CRUD操作. 2.步骤 1.创建工程勾 ...

  5. [并发编程 - socketserver模块实现并发、[进程查看父子进程pid、僵尸进程、孤儿进程、守护进程、互斥锁、队列、生产者消费者模型]

    [并发编程 - socketserver模块实现并发.[进程查看父子进程pid.僵尸进程.孤儿进程.守护进程.互斥锁.队列.生产者消费者模型] socketserver模块实现并发 基于tcp的套接字 ...

  6. date命令月日时分年

    # date +%Y/%m/%d2019/09/29[root@a-3e5 lpts-20190910-keyan-v0.2]# date +%H:%M20:00

  7. ssh安全优化免密登陆

    ssh协议 为什么使用ssh协议? 在进行传输时,会对数据进行加密,保证会话安全:telnet协议不是加密传输,在传输过程中如果被抓包,就会造成信息泄露,telnet默认不支持root远程. # 常用 ...

  8. (转)细说linux挂载

    个人觉得说的很透彻的一篇文章,深入浅出,通俗易懂,把好久之前的一些概念彻底厘清了. 转自https://www.cnblogs.com/ma5on/p/4357625.html 转载的文章不能分类 这 ...

  9. C语言printf-(转自shiney)

    1.调用格式为  printf("<格式化字符串>", <参量表>);   其中格式化字符串包括两部分内容: 一部分是正常字符, 这些字符将按原样输出; 另 ...

  10. archlinux Timeshift系统备份与还原

    安装 timeshif yay -s timeshif 备份设置 选择快照类型 此处选择[RSYNC] 选择储存位置 每台设备安装分区不一样,大家安装实际情况选择,一般选择比较大的空间存储,并且最好是 ...