版权声明:原创,未经作者允许禁止转载 https://blog.csdn.net/Mr_wuyongcong/article/details/89282043
正题
题目大意
有 个箱子放了若干个玩具,要求选择一些箱子使得 种玩具都有,求方案总数。
解题思路
设
表示选择只有在集合为
的方案数。
然后答案考虑容斥,那么答案就是
我们将集合的表示状压起来。
现在考虑如何快速求
数组,首先
(
表示集合是
的箱子个数)。
然后分治,每次分治时
肯定是若干个
比如当
时左边边都是
而右边是
。也就是右边是左边第一位变成一。那么对于每个区间就有
时间复杂度
#include<cstdio>
using namespace std;
const int M=(1<<20)+10,XJQ=1e9+7;
int n,m,f[M],w[M],p[M],ans,v[M],MS;
void apart(int l,int r)
{
if(l==r){
f[l]=v[l];
return;
}
int m=(l+r)>>1;
apart(l,m);apart(m+1,r);
for(int i=l;i<=m;i++)
f[i+m-l+1]+=f[i];
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
int z=0,k;
scanf("%d",&k);
while(k--){
int x;scanf("%d",&x);
z|=(1<<x-1);
}
v[z]++;
}
MS=1<<m;
for(int i=0;i<MS;i++)
w[i]=w[i>>1]^(i&1);
p[0]=1;
for(int i=1;i<=n;i++)
p[i]=(p[i-1]<<1)%XJQ;
apart(0,MS-1);
for(int i=0;i<MS;i++)
(ans+=((w[i]?-1:1)*(p[f[MS-i-1]]-1)))%=XJQ;
printf("%d",(ans+XJQ)%XJQ);
}