1. 程式人生 > >HDU 5117 2014ICPC北京現場賽 F - Fluorescent (狀壓DP)

HDU 5117 2014ICPC北京現場賽 F - Fluorescent (狀壓DP)

題目連結

有n個燈和m個開關,每個開關控制一些燈,顯然開關的狀態有2^m種。設亮著的燈的數目為x,求所有狀態下x^3之和。

n,m <= 50顯然不能直接計算每種x進行dp的。考慮直接計算x^3。

x^3 = (x1 + x2 + ... + xn)* (x1 + x2 + ... + xn)* (x1 + x2 + ... + xn) = Sum(xi * xj * xk)。

列舉i,j,k3個開關,然後用dp[m][S]表示用前m個開關達到狀態S的方案數,每次加上dp[m][7]即可。因為對x^3產生貢獻的條件就是xi,xj,xk同時為1也就是狀態7。

總的時間複雜度O(n^3*m)。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
typedef long long ll;

const int maxn = 55;
const ll mod = 1e9 + 7;

int t, n, m, p, x;
ll dp[maxn][8], num[maxn];

int main()
{
    scanf("%d", &t);
    int kase = 0;
    while(t--)
    {
        scanf("%d%d", &n, &m);
        memset(num, 0, sizeof(num));
        for(int i = 1;i <= m;i++)
        {
            scanf("%d", &p);
            while(p--)
            {
                scanf("%d", &x);
                num[i] |= (1LL << x);
            }
        }
        ll ans = 0;
        for(int i = 1; i<= n;i++)
        {
            for(int j = 1;j <= n;j++)
            {
                for(int k = 1;k <= n;k++)
                {
                    memset(dp, 0, sizeof(dp));
                    dp[0][0] = 1;
                    for(int o = 1;o <= m;o++)
                    {
                        for(int u = 0;u <= 7;u++)
                        {
                            int tmp = u;
                            if(num[o] & (1LL<<i)) tmp ^= 1;
                            if(num[o] & (1LL<<j)) tmp ^= 2;
                            if(num[o] & (1LL<<k)) tmp ^= 4;
                            dp[o][u] += dp[o-1][u];
                            dp[o][tmp] += dp[o-1][u];
                        }
                    }
                    ans = (ans + dp[m][7]) % mod;
                }
            }
        }
        printf("Case #%d: %lld\n", ++kase, ans);
    }
    return 0;
}