您的位置:首页 > 其它

HDU 5117 Fluorescent(状压DP)

2016-04-02 10:11 399 查看
Description

有n个灯泡,初始均为关闭状态,m个开关,每个开关可以改变一些灯泡的状态(开变关,关变开),打开每个开关的操作是随机等概率的,以X表示每次开着灯泡的数量,求E(x^3) mod 1e9+7

Input

第一行为一整数T表示用例组数,每组用例第一行为两个整数n和m分别表示灯泡数量和开关数量,之后m行每行表示一个开关控制的灯泡数量和编号

Output

对于每组用例,输出E(X^3) mod 1e9+7

Sample Input

2

2 2

1 1

2 1 2

3 1

3 1 2 3

Sample Output

Case #1: 10

Case #2: 27

Solution

以x1,x2,…,xn表示n个灯泡的状态(开1关0)

X^3=(x1+x2+…+xn)(x1+x2+…+xn)(x1+x2+…+xn)=sum(xi*xj*xk),1<=i,j,k<=n

固定i,j,k,以dp[s][t]表示操作前s个开关后这三个灯泡的开闭状态为t的情况数(0<=t<=7),那么有dp[s][t]=dp[s-1][t]+dp[s-1][t^temp],其中temp为第s个开关对这三个灯泡操作的状态(例如temp=7表示打开这三个开关,temp=3表示打开前两个灯泡),此处dp数组第一位还可以滚动来节省空间

枚举i,j,k,累加dp[m][7]即为答案

Code

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
#define maxn 55
#define mod 1000000007ll
typedef long long ll;
int T,n,m,flag[maxn][maxn];
ll dp[2][8];
int main()
{
scanf("%d",&T);
for(int Case=1;Case<=T;Case++)
{
int num,temp;
memset(flag,0,sizeof(flag));
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
scanf("%d",&num);
while(num--)
{
scanf("%d",&temp);
flag[i][temp-1]=1;
}
}
ll ans=0;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
for(int k=0;k<n;k++)
{
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(int s=0;s<m;s++)
{
temp=flag[s][i]+2*flag[s][j]+4*flag[s][k];
for(int t=0;t<8;t++)
dp[(s+1)%2][t]=(dp[s%2][t]+dp[s%2][t^temp])%mod;
}
ans=(ans+dp[m%2][7])%mod;
}
printf("Case #%d: %lld\n",Case,ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: