题意:n盏灯,m个开关,每个开关控制一些灯,用1表示控制,0表示不控制,异或为1时这盏灯亮,每个开关可开可不开,概率相同。现在问E(x^3)*(2^m),E为期望,x为亮灯数。
分析:如果求的是E[x]*(2^m),则可以考虑每一盏灯的状态,O(m)求出使这盏灯亮的方案数。
现在求每种方案下,(x1+x2+x3+...+xn)^3,用0表示不亮,1表示亮,展开即为C*xi*xj*xk,当i,j,k两两不同时C=6,一对相同时C=3,全部相同时C=1。
这样就考虑每3盏灯的状态,O(m)求出,累加即可。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<ostream>
#include<istream>
#include<algorithm>
#include<queue>
#include<string>
#include<cmath>
#include<set>
#include<map>
#include<stack>
#include<vector>
#define fi first
#define se second
#define ll long long
#define pii pair<int,int>
#define inf (1<<30)
#define eps 1e-8
#define pb push_back
#define debug puts("=====")
using namespace std;
const int maxn=100005;
const ll mod=1000000007;
int n,m;
int f[55][55];
ll dp[2][2][2][2];
int main()
{
int cas=1;
int t;
int k,a;
scanf("%d",&t);
while(t--) {
scanf("%d%d",&n,&m);
memset(f,0,sizeof(f));
for(int i=1;i<=m;i++) {
scanf("%d",&k);
while(k--) {
scanf("%d",&a);
f[i][a]=1;
}
}
ll ans=0;
for(int i=1;i<=n;i++) {
for(int j=i;j<=n;j++) {
for(int k=j;k<=n;k++) {
memset(dp,0,sizeof(dp));
int now=0;
dp[0][0][0][0]=1;
for(int e=1;e<=m;e++) {
memset(dp[now^1],0,sizeof(dp[now^1]));
for(int a=0;a<2;a++) {
for(int b=0;b<2;b++) {
for(int c=0;c<2;c++) {
dp[now^1][a][b][c]+=dp[now][a][b][c];
dp[now^1][a][b][c]%=mod;
dp[now^1][a^f[e][i]][b^f[e][j]][c^f[e][k]]+=dp[now][a][b][c];
dp[now^1][a^f[e][i]][b^f[e][j]][c^f[e][k]]%=mod;
}
}
}
now^=1;
}
if(i!=j && j!=k && i!=k) {
ans+=dp[now][1][1][1]*6;
ans%=mod;
}
else if(i==j && j==k) {
ans+=dp[now][1][1][1];
ans%=mod;
}
else {
ans+=dp[now][1][1][1]*3;
ans%=mod;
}
//cout<<i<<" "<<j<<" "<<k<<" "<<ans<<endl;
}
}
}
printf("Case #%d: %I64d\n",cas++,ans);
}
return 0;
}