题目链接:http://community.topcoder.com/stat?c=problem_statement&pm=14070&rd=16551
大致题意:
描述太麻烦。摘取关键题意:
When pushing the trees, Limak always follows a few rules:
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 ; } };