TOJ4505: KOSARE
TOJ4505: KOSARE
Total Submit: 11 Accepted:3
Description
Mirko found N boxes with various forgotten toys at his attic. There are M different toys, numbered 1 through M, but each of those can appear multiple times across various boxes.
Mirko decided that he will choose some boxes in a way that there is at least one toy of each kind present, and throw the rest of the boxes away.
Determine the number of ways in which Mirko can do this.
Input
The first line of input contains two integers N and M (1 ≤ N ≤ 1 000 000, 1 ≤ M ≤ 20).
Each of the following N lines contains an integer Ki (0 ≤ Ki ≤ M) followed by Ki distinct integers from interval [1, M], representing the toys in that box.
Output
The first and only line of output should contain the requested number of ways modulo 1 000 000 007.
Sample Input
3 3
3 1 2 3
3 1 2 3
3 1 2 3
Sample Output
7
Source
你有n个盒子,然后有m种物品。每个盒子各有K个物品,你有多少种方式拿盒子,把东西都拿完
那天我的思路就是去统计这些盒子的状态然后去容斥,显然是爆炸的
这个要用到那个集合的那个知识,n个元素的他的子集有2^n个,也就是幂集,在这个基础上枚举子集容斥就可以省掉很多步骤
来看一下这个状态压缩的道理吧
之前做过求两个数字有相同数位的对数,那个把每个数直接变为2^digit,找到每一位的hash值,然后把每个数都减1,这样1对应1,2对应2,20对应2^19,这些数加起来是2^20-1,所以数组开到1<<20即可
每个盒子所对应的hash值知道了,我要和另一个盒子的东西看他们一样么,可以这样想,和他肯定不同的会是谁呢,就是从L开始到枚举的那个中间值(L+R)>>1,mi+i-L肯定是和i是相关的,要进行加法计算,但是我有些子集是重复的,需要枚举重新减去
#include<stdio.h>
typedef __int64 ll;
const ll MD=1e9+;
ll a[];
ll po(int n)
{
ll ans=,b=;
while(n)
{
if(n&)ans=ans*b%MD;
b=b*b%MD;
n>>=;
}
return ans;
}
void la(int L,int R)
{
if(L+==R)
{
a[L]=po(a[L]);
return;
}
int mi=(L+R)>>;
for(int i=L; i<mi; i++)
a[mi+i-L]+=a[i];
la(L,mi);
la(mi,R);
for(int i=L; i<mi; i++)
{
a[mi+i-L]-=a[i];
if(a[mi+i-L]<)a[mi+i-L]+=MD;
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=,k; i<n; i++)
{
scanf("%d",&k);
int f=;
for(int j=,x; j<k; j++)
{
scanf("%d",&x);
f|=(<<(--x));
}
a[f]++;
}
la(,<<m);
printf("%I64d",a[(<<m)-]);
}
这个怎么省去加这个状态呢,就是提前进行一次二进制枚举
#include<stdio.h>
typedef __int64 ll;
const ll MD=1e9+;
ll a[];
ll po(int n)
{
ll ans=,b=;
while(n)
{
if(n&)ans=ans*b%MD;
b=b*b%MD;
n>>=;
}
return ans;
}
void la(int L,int R)
{
if(L+==R)
{
a[L]=po(a[L]);
return;
}
int mi=(L+R)>>;
la(L,mi);
la(mi,R);
for(int i=L; i<mi; i++)
{
a[mi+i-L]-=a[i];
if(a[mi+i-L]<)a[mi+i-L]+=MD;
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
int ff=<<m,f;
for(int i=,k; i<n; i++)
{
scanf("%d",&k);
f=;
for(int j=,x; j<k; j++)
{
scanf("%d",&x);
f|=(<<(--x));
}
a[f]++;
}
for(int i=; i<m; i++)
for(int s=; s<ff; s++)
if(s&(<<i))
a[s]+=a[s^(<<i)];
la(,ff);
printf("%I64d",a[ff-]);
}
直接位运算去统计,这个算法速度最快
#include<stdio.h>
const int N=<<,MD=1e9+;
int cnt[N],B[N],n,m,ans[N],f;
int main()
{
scanf("%d%d",&n,&m);
f=<<m;
B[]=;
for(int i=; i<=n; i++)
B[i]=(B[i-]<<)%MD;
for(int i=,t,x,s; i<n; i++)
{
scanf("%d",&t);
s=;
while(t--)
scanf("%d",&x),s|=<<x-;
cnt[s]++;
}
for(int i=; i<m; i++)
for(int s=; s<f; s++)
if(s&<<i)
cnt[s]+=cnt[s^<<i];
for(int s=; s<f; s++)
ans[s]=B[cnt[s]];
for(int i=; i<m; i++)
for(int s=; s<f; s++)
if(s&<<i)
ans[s]=(ans[s]-ans[s^<<i]+MD)%MD;
printf("%d",ans[f-]);
return ;
}
TOJ4505: KOSARE的更多相关文章
随机推荐
- Linux系统日志分析
Linux系统拥有非常灵活和强大的日志功能,可以保存几乎所有的操作记录,并可以从中检索出我们需要的信息. 大部分Linux发行版默认的日志守护进程为 syslog,位于 /etc/syslog 或 / ...
- java uuid第一次性能
在java中产生uuid的方式是使用java.util.UUID. UUID.randomUUID().toString(); 我在测试redis性能时,使用uuid产生测试数据,发现多线程测试red ...
- uva 10328 - Coin Toss 投硬币(dp递推,大数)
题意:抛出n次硬币(有顺序),求至少k个以上的连续正面的情况的种数. 思路:转换成求抛n个硬币,至多k-1个连续的情况种数,用所有可能出现的情况种数减去至多k-1个的情况,就得到答案了.此题涉及大数加 ...
- GWTDesigner_v5.1.0破解码
GWTDesigner_v5.1.0_win32_x86.exe破解码,双击运行keygeno.jar,然后输入用户名.网卡MAC,然后单击Generate,将生成的文件放在C:\Documents ...
- 2012-2013 ACM-ICPC, NEERC, Central Subregional Contest J Computer Network1 (缩点+最远点对)
题意:在连通图中,求一条边使得加入这条边以后的消除的桥尽量多. 在同一个边双连通分量内加边肯定不会消除桥的, 求边双连通分量以后缩点,把桥当成边,实际上是要选一条最长的链. 缩点以后会形成一颗树,一定 ...
- 关系代数演算So Easy
关系代数运算So Easy 关系代数是以关系为运算的一组高级运算的集合.由于定义为属性个数 相同的元组的集合,因此集合代数的操作就可以引入到关系代数中.关系代数也可以看做是一种抽象的查询语言,是对关系 ...
- [torch] torch.contiguous
torch.contiguous 作用 连续存储,因为view的操作要求的是连续的内容. 详细 考虑下面的操作,transpose操作只是改变了stride,而实际数组存储的内容并没有得到任何改变,即 ...
- [论文理解]Region-Based Convolutional Networks for Accurate Object Detection and Segmentation
Region-Based Convolutional Networks for Accurate Object Detection and Segmentation 概括 这是一篇2016年的目标检测 ...
- falling object思路总结
1.用检测的方法把falling object标记为一个类别,然后检测出类别.这种方式不可行的原因:因为falling object可能是任何东西,所以可能是一个路锥,也可能是一个玻璃瓶,还可能是掉下 ...
- iOS开发遇到的坑之六--使用cocopods管理第三方库时,编译出现Library not found for -lPods问题的解决办法
在项目中有时候会遇到Library not found for -lPods(这里的IPods指的是你具体的第三方库)的问题 出现这个错误的原因是:xcode在编译的时候找不到这个库,从而导致项目无法 ...