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 ;
   }
};



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值