这道题给你一个开关控制灯灭灯亮的模型。
首先考虑期望值为E(x)*2^m的情况,不难想到,用0表示灯灭1表示灯亮,也就是简单的状压的思想,分别递推求出每个灯亮的情况有多少种方法。
对于期望值为E(x^3)*2^m的拓展,也就是原题要求的,其实就可以变成一个数学展开模型。
X=(X0+X1+X2+X3+...+Xn-1), Xi表示i号灯是灭是亮。
X^3=(X0+X1+X2+X3+...+Xn-1)^3 数学展开以后其实就是每个Cijk*Xi*Xj*Xk (0<=i,j,k<n),C是常数表示ijk的这样排列有多少种,不妨设i<=j<=k,如果i=j=k就取1,i!=j!=k就取6,因为P(3,3)等于6,如果i=j!=k || i!=j=k 就取3,因为P(3,3)/2!=3。
所以算个状压dp[si][sj][sk]表示当前i j k三灯亮灭状态为si sj sk,压缩成状态S,可以用m个开关控制状态转移,边转移边累加答案。
13532250 | 2015-04-23 09:02:28 | Accepted | 5117 | 187MS | 1572K | 1585 B | G++ | howardcn |
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int mod = 1000000007;
typedef long long LL;
LL dp[2][8];
int f[51][51];
int main()
{
// freopen("data.in","r",stdin);
int T,N,M,K,l,now;
LL tmp;
scanf("%d",&T);
for(int cas=1;cas<=T;cas++){
LL ans=0;
scanf("%d%d",&N,&M);
memset(f,0,sizeof f);
for(int i=0;i<M;i++){
scanf("%d",&K);
for(int j=0;j<K;j++){
scanf("%d",&l);
f[i][l-1]++;
}
}
for(int i=0;i<N;i++){
for(int j=i;j<N;j++){
for(int k=j;k<N;k++){
memset(dp,0,sizeof dp);
dp[0][0]=1;
now=1;
for(int s=0;s<M;s++,now^=1){
tmp=0;
if(f[s][i]) tmp|=1;
if(f[s][j]) tmp|=2;
if(f[s][k]) tmp|=4;
for(int t=0;t<8;t++){
dp[now][t]=dp[now^1][t];
dp[now][t]+=dp[now^1][t^tmp];
dp[now][t]%=mod;
}
}
#define u dp[now^1][7]
tmp = u;
if(i!=j&&j!=k) u*=6;
else if(i==j&&j==k) ;
else u*=3;
ans=(ans+u)%mod;
}
}
}
printf("Case #%d: %I64d\n",cas,ans);
}
return 0;
}