hdu 5117 Fluorescent(状压dp+思维)

题目链接:hdu 5117 Fluorescent

题意:

有n个灯,m个开关,每个开关能控制一些灯的状态,即关闭的打开,打开的关闭。一开始灯全部是关闭的。

现在有个人去操作这些开关,显然会有2^m次组合。

现在问这个人操作完这些开关后,亮着的灯的期望E(x)

但是题目要求输出的是E(x^3)*2^m%(1e9+7)。

题解:

首先我们先来考虑求E(x)。

显然就是将这2^m种开关的开闭组合求出来每种情况的灯亮着的个数和sum(x),

然后sum(x)/(2^m)就是E(x)。

这个怎么求呢。

考虑在这2^m次中,每栈灯的贡献。

考虑dp[i][j][2],表示前j个开关能将第i栈灯开启和关闭的方案数。

那么dp[i][j][1]就是第i栈灯的贡献。

现在考虑求E(x^3)*2^m。

显然就是就那个sum(x^3)。

设x=a1+a2+……+an ,ai  代表第i栈灯亮与不亮的情况。

那么x^3=(a1+a2+……+an)*(a1+a2+……+an)*(a1+a2+……+an)。

展开就是Σ(ai*aj*a)。

所以我们考虑枚举i,j,k,然后将i,j,k的状态压缩起来。

然后求解贡献的思路就和上面一样了。

 1 #include<bits/stdc++.h>
 2 #define F(i,a,b) for(int i=(a);i<=(b);++i)
 3 #define mst(a,b) memset(a,b,sizeof(a))
 4 using namespace std;
 5 typedef long long ll;
 6 
 7 const int N=57,P=1e9+7;
 8 int t,n,m,ans,cas,dp[8][N],num,x;
 9 ll sw[N];
10 
11 void up(int &a,int b){a+=b;if(a>=P)a-=P;}
12 
13 int main(){
14     scanf("%d",&t);
15     while(t--)
16     {
17         scanf("%d%d",&n,&m),mst(sw,0),ans=0;
18         F(i,1,m)
19         {
20             scanf("%d",&num);
21             F(j,1,num)scanf("%d",&x),sw[i]|=1ll<<x;
22         }
23         F(i,1,n)F(j,1,n)F(k,1,n)
24         {
25             mst(dp,0);
26             dp[0][0]=1;
27             F(l,0,m-1)F(u,0,7)if(dp[u][l])
28             {
29                 int nxt=u;
30                 if(sw[l+1]&(1ll<<i))nxt^=1;
31                 if(sw[l+1]&(1ll<<j))nxt^=2;
32                 if(sw[l+1]&(1ll<<k))nxt^=4;
33                 up(dp[nxt][l+1],dp[u][l]);//
34                 up(dp[u][l+1],dp[u][l]);//
35             }
36             up(ans,dp[7][m]);
37         }
38         printf("Case #%d: %d\n",++cas,ans);
39     }
40     return 0;
41 }
View Code

 

posted @ 2017-10-04 21:52  bin_gege  阅读(225)  评论(0编辑  收藏  举报