Xi表示第i个灯最后亮不亮,亮为1,不亮为0。
所以X=∑Xi,X^3=(X1+X2……)(X1+X2……)(X1+X2……);
根据期望的线性性,考虑每一项XiXjXk的贡献。
当且仅当i,j,k都亮时,贡献为1。
对灯i,用一个bitset维护能改变它状态的开关集合。第p位为1表示第p个开关能改变灯i的状态。
对i,j,k三个灯,求出能同时改变三个灯状态的个数c,能改变两个灯状态的个数b1,b2,b3,能改变一个灯状态的个数a1,a2,a3,和都不能改变的个数cnt=m-c-b1-b2-b3-a1-a2-a3;
对于都不能改变的,这些开关状态可以任意,所以最后乘上(1<<cnt)。
对于能改变的,我用的纯暴力。。。。。
枚举C,B1,B2,B3分别表示在c,b1,b2,b3中开几个开关。
根据d1=C+B1+B2的奇偶性,可以知道在a1中要开奇数个还是偶数个。根据二项式定理,取奇数个和偶数个方案数相同,都是(1<<(a1-1));(注意d1为0时,里面至少要取1)
d2,d3同理。
然后因为暴力枚举i,j,k全不同会出现6次,两个相同会出现3次,都相同会出现1次,所以枚举的时候让i<=j<=k可以常数优化。
#include<cstdio>
#include<algorithm>
#include<bitset>
using namespace std;
#define ll long long
const ll mod=1e9+7;
int n,m;
ll two[56],CC[56][56];
bitset<56>a[56],tmp;
int main()
{
int icase=0;
two[0]=1;
for(int i=1;i<=53;i++)two[i]=two[i-1]*2%mod;
for(int i=0;i<=53;i++)
{
CC[i][0]=1;
for(int j=1;j<=i;j++)
{
CC[i][j]=CC[i-1][j]+CC[i-1][j-1];
if(CC[i][j]>=mod)CC[i][j]-=mod;
}
}
int _;scanf("%d",&_);
while(_--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)a[i].reset();
int cnt;
for(int i=1;i<=m;i++)
{
scanf("%d",&cnt);
for(int j=1;j<=cnt;j++)
{
int x;
scanf("%d",&x);
a[x].set(i);
}
}
ll ans=0;
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
for(int k=j;k<=n;k++)
{
tmp=a[i]&a[j]&a[k];
int c=tmp.count();
int b1=((a[i]&a[j])^tmp).count();
int b2=((a[j]&a[k])^tmp).count();
int b3=((a[k]&a[i])^tmp).count();
int a1=a[i].count()-c-b1-b3;
int a2=a[j].count()-c-b1-b2;
int a3=a[k].count()-c-b2-b3;
ll sum=0;
for(int C=0;C<=c;C++)
for(int B1=0;B1<=b1;B1++)
for(int B2=0;B2<=b2;B2++)
for(int B3=0;B3<=b3;B3++)
{
int d1=C+B1+B3,d2=C+B1+B2,d3=C+B2+B3;
ll mul=CC[c][C]*CC[b1][B1]%mod*CC[b2][B2]%mod*CC[b3][B3]%mod;
ll tmp1,tmp2,tmp3;
if(a1>=1)tmp1=two[a1-1];
else if(d1&1)tmp1=1;
else tmp1=0;
if(a2>=1)tmp2=two[a2-1];
else if(d2&1)tmp2=1;
else tmp2=0;
if(a3>=1)tmp3=two[a3-1];
else if(d3&1)tmp3=1;
else tmp3=0;
sum+=tmp1*tmp2%mod*tmp3%mod*mul%mod;
if(sum>=mod)sum-=mod;
}
ll cnt=6;
if(i==j&&j==k)cnt=1;
else if(i==j||j==k||i==k)cnt=3;
ans+=sum*two[m-c-a1-a2-a3-b1-b2-b3]%mod*cnt%mod;
if(ans>=mod)ans-=mod;
}
printf("Case #%d: %I64d\n",++icase,ans);
}
return 0;
}