TOJ4505: KOSARE 

Time Limit(Common/Java):10000MS/30000MS     Memory Limit:65536KByte
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

COCI 2011/2012 Contest #6

你有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的更多相关文章

随机推荐

  1. OCX和DLL的区别

    转自:http://blog.csdn.net/scucj/archive/2006/06/29/852181.aspx OCX和DLL的区别 一.关于DLL的介绍      DLL,动态链接库,Dy ...

  2. cv2.bilateralFilter 双边滤波

    双边滤波bilateralFilter 双边滤波是一种非线性的滤波方法,是结合图像的空间邻近度和像素值相似度的一种折衷处理,同时考虑空间与信息和灰度相似性,达到保边去噪的目的,具有简单.非迭代.局部处 ...

  3. 【转】iOS开发-文件管理(一)

    iOS开发-文件管理(一) 一.iOS中的沙盒机制 iOS应用程序只能对自己创建的文件系统读取文件,这个独立.封闭.安全的空间,叫做沙盒.它一般存放着程序包文件(可执行文件).图片.音频.视频.pli ...

  4. MySQL 数据备份与还原的示例代码

    MySQL 数据备份与还原的示例代码 这篇文章主要介绍了MySQL 数据备份与还原的相关知识,本文通过示例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下 一.数据备份 1.使用 ...

  5. (转发)IOS高级开发~Runtime(二)

    一些公用类: @interface ClassCustomClass :NSObject{ NSString *varTest1; NSString *varTest2; NSString *varT ...

  6. [vijos]P1979 NOIP2015 信息传递

    描述 有 n 个同学(编号为 1 到 n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为 i 的同学的信息传递对象是编号为 TiTi 的同学. 游戏开始时,每人都只知道 ...

  7. 【莫队】bzoj4542: [Hnoi2016]大数

    挺有意思的,可以仔细体味一下的题:看白了就是莫队板子. Description 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345.小 ...

  8. 22.Yii2.0框架多表关联一对一查询之hasOne

    思路: 通过文章查它对应的分类信息 一对一的关系 控制器里 //一对一关联查询 public function actionRelatesone() { //方法一,hasOne() 用查一条文章的结 ...

  9. OpenCV中的图像形态学转换

    两个基本的形态学操作是腐蚀和膨胀.他们的变化构成了开运算,闭运算,梯度等.下面以这张图为例 1.腐蚀 这个操作会把前景物体的边界腐蚀掉. import cv2 import numpy as np i ...

  10. 线段树:CDOJ1591-An easy problem A (RMQ算法和最简单的线段树模板)

    An easy problem A Time Limit: 1000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) Pr ...