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*ak )。
所以我们考虑枚举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 }