HDU 5117 Fluorescent
题目链接:HDU-5117
题意为有n盏灯,m个开关,每个开关控制着\( k_{i} \)灯。X为最后亮着的灯的个数,要求出\( E(X^{3} ) * 2^{M} mod (10^9 + 7) \)。
可以看出\( E(X^{3} ) * 2^{M} = \sum (X^{3} * (\frac{1}{2})^{m}) * 2^{m} = \sum X^{3} \)
然后将 \( \sum X^{3} \) 分解为\( \sum X^{3} = \sum_{i,j,k = 1}^{n} x_{i} * x_{j} * x_{k} \)
于是问题就转化成了求对于所有的i,j,k,有多少种情况i,j,k都亮着。
于是我们可以写出状态转移方程f[i][j][k][state][ii] = f[i][j][k][state][ii-1] + f[i][j][k][state ^ \( switch_{ii}\)][ii-1];
其中f[i][j][k][state][ii]表示使用前ii个开关使i,j,k的状态为state的方案数。
我们发现i,j,k其实没有必要记录。所以进一步,我们可以把方程优化为f[state][ii] = f[state][ii-1] + f[state ^ switch[ii]][ii-1];
另外还有一个需要注意的小细节是注意使用1LL。
代码如下:
1 #include<cstdio> 2 #include<set> 3 #include<map> 4 #include<cstring> 5 #include<algorithm> 6 #include<queue> 7 #include<iostream> 8 using namespace std; 9 typedef long long LL; 10 11 const LL MOD = 1e9 + 7; 12 const LL MAXN = 60; 13 LL d[MAXN]; 14 int main() 15 { 16 #ifdef LOCAL 17 freopen("in.txt","r",stdin); 18 #endif 19 LL t; 20 scanf("%lld",&t); 21 for(LL tt = 1; tt <= t; tt++) 22 { 23 memset(d,0,sizeof(d)); 24 LL n,m; 25 scanf("%lld%lld", &n, &m); 26 for(LL i = 1; i <= m; i++) 27 { 28 LL k; 29 scanf("%lld", &k); 30 for(LL j = 1; j <= k; j++) 31 { 32 LL tmp; 33 scanf("%lld", &tmp); 34 d[i] += (1LL << (tmp-1)); 35 } 36 } 37 LL ans=0; 38 for(LL i = 1; i <= n; i++) 39 for(LL j = 1; j <= n; j++) 40 for(LL k = 1; k <= n; k++) 41 { 42 LL f[8][MAXN]; 43 memset(f,0,sizeof(f)); 44 f[0][0]=1; 45 for(LL ii = 1; ii <= m; ii++) 46 { 47 LL ss=0; 48 if(d[ii] & (1LL << (i-1))) ss ^= 1; 49 if(d[ii] & (1LL << (j-1))) ss ^= 2; 50 if(d[ii] & (1LL << (k-1))) ss ^= 4; 51 for(LL jj=0;jj<=7;jj++) 52 { 53 f[jj][ii] += f[jj][ii-1]; 54 f[jj][ii] += f[jj ^ ss][ii - 1]; 55 } 56 } 57 ans = (ans + f[7][m]) % MOD; 58 //printf("%lld %lld %lld %lld\n", i, j, k, ans); 59 } 60 printf("Case #%lld: %lld\n", tt, ans); 61 } 62 return 0; 63 }