版权声明:欢迎dalao指出错误暴踩本SD,蒟蒻写的博客转载也要吱一声 https://blog.csdn.net/enjoy_pascal/article/details/89366186
description
ABC找到N个箱子,箱子里装着一些玩具,一共有M种玩具,编号从1到M,同一种玩具可能出现在多个箱子里。
ABC决定从中选择一些箱子,把这些箱子中的玩具聚集到一起,必须保证每种玩具至少出现一次。
问ABC一共有多少种选择方案。
analysis
-
对于 种玩具的选择情况,可以 枚举哪些位没有玩具算答案
-
哪些位没有玩具,相当于其他位都有玩具,本质上一样
-
设 表示选 集合玩具的方案数,那么 表示不选 集合玩具的方案数
-
对于分治求 ,可以发现 ,那么把左半边累加到相应的右半边即可
-
答案为
code
#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 1000005
#define MAXM (1<<20)+5
#define mod 1000000007
#define ll long long
#define reg register ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;--i)
#define O3 __attribute__((optimize("-O3")))
using namespace std;
ll f[MAXM],g[MAXM],pow[MAXN];
ll n,m,MAX,ans;
O3 inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
O3 inline void dfs(ll l,ll r)
{
if (l==r){f[l]=g[l];return;}
ll mid=(l+r)>>1;
dfs(l,mid),dfs(mid+1,r);
fo(i,l,mid)f[i-l+mid+1]+=f[i];
}
O3 int main()
{
//freopen("T2.in","r",stdin);
n=read(),m=read(),MAX=1<<m;
fo(i,1,n)
{
ll m=read(),S=0;
while (m--)S|=1<<(read()-1);
++g[S];
}
dfs(0,MAX-1),pow[0]=1;
fo(i,1,n)pow[i]=pow[i-1]*2%mod;
g[0]=1;
fo(i,0,MAX-1)
{
g[i]=g[i>>1]*(i&1?-1:1);
ans=(ans+g[i]*(pow[f[MAX-i-1]]-1)%mod)%mod;
}
printf("%lld\n",(ans%mod+mod)%mod);
return 0;
}