版权声明:虽然本蒟蒻很菜,但各位dalao转载请注明出处谢谢。 https://blog.csdn.net/xuxiayang/article/details/89281858
给定 个子,要求选出若干个箱子,这些箱子中的玩具必须齐全( 件),求方案数,答案对 取模
数据范围:
首先很容易想到状压 ,这样做状压 就有50分了
这样子的复杂度显然还是不够优秀,由于求全部齐全的比较麻烦,但我们可以用容斥求出至少少一个的方案数,再用 一减去即为答案了
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define N (1<<m)
#define mod 1000000007
using namespace std;
int c[1<<20],w[1<<20],f[1<<20],p[1<<20]={1},n,m,ans=0,s,k;
inline long long read()
{
char c;int f=0,d=1;
while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
return d*f;
}
void cdq(int l,int r)
{
if(l==r)
{
f[l]=c[l];
return;
}
int m=l+r>>1;
cdq(l,m);cdq(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(register int i=1;i<=n;i++)
{
k=read();s=0;
for(register int j=1;j<=k;j++) s|=1<<(read()-1);
c[s]++;
}
for(register int i=1;i<N;i++) w[i]=w[i>>1]^(i&1);
for(register int i=1;i<=n;i++) p[i]=(p[i-1]<<1)%mod;
cdq(0,N-1);
for(register int i=0;i<N;++i) ans=w[i]?(ans-p[f[N-i-1]]+1)%mod:(ans+p[f[N-i-1]]-1)%mod;
printf("%d",(ans+mod)%mod);
}