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. python3操作mysql数据库表01(基本操作)

    #!/usr/bin/env python# -*- coding:UTF-8 -*- import requestsfrom bs4 import BeautifulSoupfrom bs4 imp ...

  2. JavaScript 的 parseInt 取整

    http://www.neoease.com/javascript-get-integer-via-parseint/ JavaScript 是弱类型语言, 为了保证数值的有效性, 在处理数值的时候, ...

  3. 2017.10.5 QBXT 模拟赛

    题目链接 T1 从小到大排序,用sum记录前缀和,然后枚举1~n个数 ,如果当前的前缀和 + 1小于a[i]的话 那么 sum + 1永远不可能拼出来 直接输出sum + 1 ,否则统计前缀和.最后如 ...

  4. C# 生成条形码图片

    在网上看到一些人写关于条形码的代码都很长,有的甚至拿来卖,所以查了下资料,希望能对大家有帮助. 我的实现原理是: 其实Windows本身就有一个字体是用来显示条形码的. 只要将数字改为这种字体就变成了 ...

  5. 用NPOI操作EXCEL-锁定列CreateFreezePane()

    public void ExportPermissionRoleData(string search, int roleStatus) { var workbook = new HSSFWorkboo ...

  6. JavaScript内存泄露,闭包内存泄露如何解决

    本文原链接:https://cloud.tencent.com/developer/article/1340979 JavaScript 内存泄露的4种方式及如何避免 简介 什么是内存泄露? Java ...

  7. orcle定时备份

    orcle定时备份 (1)写个.bat文件 例如: exp test/test@ORCL file=f:\back\test%date:~,%%date:~,%%date:~,%.dmp (2)开始, ...

  8. MFC中获得各种指针概述(个人觉得是很重要的重点)

    前言:这学期学习MFC(有点过时的东西),上课时,老师讲到获取当前活动指针,获取视图指针,文档指针,文档模板指针等(已晕) 后来下来真正写代码的时候发现这些几乎都是需要用到的东西,所以特此记录下,让自 ...

  9. cocostudio的bug(1)

    今天有个女同事问我一个问题,两个cocostudio的ui同时addChild到一个layer上面,高层级的ui设置visible为false,低层级的ui设置的visible设置为true,然后低层 ...

  10. OC中的宏定义

    我们都知道,宏定义是编译期常量.而OC是一种动态语言. 1.iOS系统版本判断的两个宏定义 __IPHONE_OS_VERSION_MAX_ALLOWED // iOS系统版本最大允许 __IPHON ...