设
x
i
x_i
xi为灯x是否打开(0关1开),那么就有如下转换:
(
∏
i
=
1
n
x
i
)
3
=
∑
i
=
1
n
∑
i
=
1
n
∑
i
=
1
n
x
i
x
j
x
k
(\prod\limits_{i=1}^nx_i)^3=\sum\limits_{i=1}^n\sum\limits_{i=1}^n\sum\limits_{i=1}^nx_ix_jx_k
(i=1∏nxi)3=i=1∑ni=1∑ni=1∑nxixjxk
根据期望的可加性,可以单独算每对i,j,k的贡献。对每对用状压dp算一下贡献即可。
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
#define wzh(x) cerr<<#x<<'='<<x<<endl;
int t,n,m,cas,s[55],v[55][55];
int dp[2][8];
const int mod=1e9+7;
int add(int x,int y){
x+=y;
if(x>=mod)x-=mod;
return x;
}
int main() {
ios::sync_with_stdio(false);
for(cin>>t,cas=1;cas<=t;cas++){
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>s[i];
for(int j=1;j<=s[i];j++){
cin>>v[i][j];
}
}
int ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
for(int k=1;k<=n;k++){
vector<int>re={i,j,k};
for(int f=0;f<8;f++)dp[0][f]=dp[1][f]=0;
dp[0][0]=1;
int sta=0;
for(int res=1;res<=m;res++){
int now=0;
for(int nxt=0;nxt<8;nxt++)dp[sta^1][nxt]=0;
for(int x=0;x<3;x++){
for(int y=1;y<=s[res];y++){
if(v[res][y]==re[x]){
now+=1<<x;
break;
}
}
}
for(int nxt=0;nxt<8;nxt++)dp[sta^1][nxt^now]=dp[sta][nxt];
for(int nxt=0;nxt<8;nxt++)dp[sta^1][nxt]=add(dp[sta^1][nxt],dp[sta][nxt]);
sta^=1;
}
ans=add(ans,dp[sta][7]);
}
}
}
cout<<"Case #"<<cas<<": "<<ans<<'\n';
}
return 0;
}