Single Round Match 671 Round 1 - Division II, Level Three(状压DP)(略难)

题目链接:http://community.topcoder.com/stat?c=problem_statement&pm=14070&rd=16551

大致题意:

描述太麻烦。摘取关键题意:

When pushing the trees, Limak always follows a few rules:

  • He only pushes trees in two directions: either southwards or eastwards.
  • He will never push a tree in a way that would cause it to fall out of the forest. For example, he will never push a tree in the last column eastwards.
  • He will never push a tree in a way that would produce two fallen trees lying on the same cell.

  1. Is there a fallen tree in the current cell? If yes, there is no room here to do anything, so I'll just move to the next cell.
  2. Can I push the tree in the direction that is given by the letter written on the tree? If yes, I'll do so and move to the next cell.
  3. Can I push the tree in the other direction? If yes, I'll do so and move to the next cell.
  4. I'll move to the next cell without pushing the tree.

You are given the ints  W  and  H . There are 2^( W * H ) different forests with these dimensions. (Different forests have different assignments of letters S and E to the trees.) For each of these forests, compute the number of trees Limak would topple. Return the sum of those 2^( W * H ) numbers, modulo  MOD .


思路:

第一行状压01表示S和E,然后某些树会倒在第二行上,把倒下的位置状压转移到第二行。

每一行产生的贡献值之和这行SE和上一行倒下的树产生的影响。

所以可以dp[premask][curmask].first 表示上一行产生的影响是premask,这行SR分布是curmask时,可以推倒多少颗树木

dp[premask][curmask].second 表示推倒这些树木后对下一行产生的影响

然后统计总和纪录到此行为止,cnt[mask]一共贡献了多少答案和一共有多少种方式产生这个mask,方便接下来用乘法原理递推每一行

复杂度是O( (2^W) * (2^W) * H)

// Paste me into the FileEdit configuration dialog
// Paste me into the FileEdit configuration dialog

#include <iostream>
#include <cstring>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <ctime>
#include <bitset>
#include <algorithm>
#define SZ(x) ((int)(x).size())
#define ALL(v) (v).begin(), (v).end()
#define foreach(i, v) for (__typeof((v).begin()) i = (v).begin(); i != (v).end(); ++ i)
#define reveach(i, v) for (__typeof((v).rbegin()) i = (v).rbegin(); i != (v).rend(); ++ i)
#define REP(i,n) for ( int i=1; i<=int(n); i++ )
#define rep(i,n) for ( int i=0; i< int(n); i++ )
using namespace std;
typedef long long ll;
#define X first
#define Y second
#define PB push_back
#define MP make_pair
typedef pair<ll,ll> pii;

const int N = 8;
pii dp[1<<N][1<<N];
bool ok[N];
pii cnt[1<<N][2]; // X - > kind, Y -> sum
ll last[1<<N];
class BearDestroysDiv2 {
public:
   int sumUp( int W, int H, int MOD ) {
        int n = W, m = H;
        rep(i, 1 << n) {
                ll la = 0;
                rep(j, 1 << n) {
                        memset(ok, 0, sizeof(ok));
                        int state = 0;
                        ll c = 0;
                        rep(p, n) {
                                if( i & ( 1 << p) ) continue ;
                                if( (j & (1 << p)) ) {
                                        if( ( (p == 0) || (p > 0 && ok[p-1] == 0) ) && p != n-1 && (i&(1<<(p+1)))==0){
                                                c ++;
                                                ok[p] = 1;
                                        } else if( ((p == 0)||(p > 0 && ok[p-1] == 0))) {
                                                c ++ ;
                                                state |= ( 1 << p );
                                        }
                                } else {
                                        if( ( (p == 0) || (p > 0 && ok[p-1] == 0) ) ) {
                                                c ++;
                                                state |= ( 1 << p );
                                        }
                                }
                        }
                        dp[i][j] = pii(c % MOD, state);
                        memset( ok ,0 ,sizeof(ok));
                        rep(p, n) {
                                if( i & ( 1 << p) ) continue ;
                                if( (j & (1 << p)) ) {
                                        if( ( (p == 0) || (p > 0 && ok[p-1] == 0) )&& p != n-1 && (i&(1<<(p+1)))==0  ) {
                                                la ++ ;
                                                ok[p] = 1;
                                        }
                                } else {
                                        if( ( (p == 0) || (p > 0 && ok[p-1] == 0) )&& p != n-1 && (i&(1<<(p+1)))==0 ) {
                                                la ++;
                                                ok[p] = 1;
                                        }
                                }
                        }
                }
                last[i] = la % MOD;
        }
        memset(cnt, -1 , sizeof(cnt));
        cnt[0][1].X = 1;
        cnt[0][1].Y = 0;
        for(int h = 1; h < m; h ++) {
                int cur = h & 1;
                rep(mask, 1 << n) cnt[mask][cur^1] = pii(-1, -1);
                rep(pre, 1 << n) {
                        if( cnt[pre][cur] == pii(-1,-1) ) continue ;
                        rep(mask, 1 << n) {
                                pii &ans = cnt[dp[pre][mask].Y][cur^1];
                                if( ans == pii(-1, -1) ) ans = pii(0, 0);
                                ans.X = (ans.X + cnt[pre][cur].X) % MOD;
                                ans.Y = (ans.Y + cnt[pre][cur].Y + cnt[pre][cur].X * dp[pre][mask].X) % MOD ;
                        }
                }
        }
        ll ans = 0;
        rep(mask, 1 << n) {
                if( cnt[mask][m&1] == pii(-1,-1) ) continue;
                ans = ( ans + cnt[mask][m & 1].X * last[mask] + cnt[mask][m & 1].Y * (1 << n) ) % MOD;
        }
        return ans ;
   }
};



你可能感兴趣的:(Single Round Match 671 Round 1 - Division II, Level Three(状压DP)(略难))