HDU 5117 Fluorescent


这个题简单DP可以通过,然而前面需要数学推导一下。
题意简单说一下:有n个灯泡,和m个开关,每个开关控制着一些灯的明亮,摁下一个开关,对应这个开关的那些灯泡就会翻转。每个灯有摁下和不摁下供人选择,总共2^m种选择。求所有在2^m种选择下,所有明着的灯三次方总和。

定义Xi表示第i盏灯的状态, 亮就是1 ,不亮就是0
所以求得解就是 (x1 +x2 +x3 +x4+x5+…………+xn)*(x1 +x2 +x3 +x4+x5+…………+xn)*(x1 +x2 +x3 +x4+x5+…………+xn)
当然这三个集合是一样的,把他们展开就是好多个 xi * xj * xk

这样就可以枚举所有情况了,当然是DP优化一下
dp[a][b][c][i][j]
表示 a, b, c这三个灯泡,在前i个开关,状态为j的情况下 (0<=j<8总共8种情况对应3盏灯)
这样用循环a,b,c前三维度的数组就可以省去了

DP[i][j]表示前i个开关,这三个灯,状态为j的个数

附上AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int maxn = 55;
const int maxm = 55;
const int mod = 1e9 + 7;

int K[maxm][maxn];

int T, n, m;
int kase = 0;

int tain(int x, int y, int a, int b, int c){
    if(K[x][a]==1) y^=1;
    if(K[x][b]==1) y^=2;
    if(K[x][c]==1) y^=4;
    return y;
}

int dp[maxn][8];

int main(){
    scanf("%d", &T);

    while(T--){
        scanf("%d%d", &n, &m);

        memset(K, 0, sizeof(K));
        for(int i = 1; i<=m;++i){
            int x, y;
            scanf("%d", &x);
            while(x--){
                scanf("%d", &y);
                K[i][y] = 1;
            }
        }

        int ans = 0;
        for(int a = 1; a <= n; ++a){
            for(int b = 1; b <= n; ++b)
            for(int c = 1; c <= n; ++c){
                for(int i = 0; i<8; ++i)
                    dp[0][i] = (i==0);

                for(int i = 1; i<=m; ++i){
                    for(int j = 0; j<8; ++j){
                        dp[i][j] = dp[i-1][j] + dp[i-1][tain(i, j, a, b, c)];
                        if(dp[i][j]>=mod) dp[i][j]%=mod;
                    }
                }

                ans = (ans +dp[m][7])%mod;
            }
        }
        printf("Case #%d: %d\n", ++kase, ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值