[ural1519]Formula 1 && 插头DP(括号表示法)

只是换了一种方法来表示方法 但是括号表示好像跑得快些 

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
#define SF scanf
#define PF printf
#define bit(x) (1<<(x))
#define getbit(x, y) (((x) >> mov[y]) & 3)
#define BIT(x, y) ((x) << mov[y])
#define clrbit(x, i, j) ((x) & (~(3 << mov[i])) & (~(3 << mov[j])))
using namespace std;
typedef long long LL;
const int MAXN = 13;
const int MAXS = 1 << 12;
const int MOD = (1<<15) - 1;
const int MAXNODE = 1000000;
const int mov[20]={0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28};
struct Hash {
	int sz, adj[MOD+10], next[MOD+10];
	int sta[MAXNODE+10];
	LL val[MAXNODE+10];
	void clr() {
		memset(adj, -1, sizeof(adj));
		for(int i = 0; i < sz; i++) val[i] = 0;
		sz = 0;
	}
	void push(int s, LL v) {
		int ss = s & MOD;
		for(int i = adj[ss]; ~i; i = next[i]) 
			if(sta[i] == s) {
				val[i] += v; return ;
			}
		val[sz] = v; sta[sz] = s; next[sz] = adj[ss]; adj[ss] = sz++;
	}
} dp[2];
int n, m, M[MAXN+10][MAXN+10], ex, ey, cur;
int FindL(int st, int x) {
	int cnt = 1;
	for(int i = x-1; i >= 0; i--) {
		int s = ((st >> mov[i]) & 3);
		if(s == 2) cnt++;
		else if(s == 1) cnt--;
		if(!cnt) return i;
    }
	return -1;
}
int FindR(int st, int x) {
	int cnt = 1;
	for(int i = x+1; i <= m; i++) {
		int s = ((st >> mov[i]) & 3);
		if(s == 1) cnt++;
		else if(s == 2) cnt--;
		if(!cnt) return i;
	}
	return -1;
}
LL solve() {
	cur = 0; dp[0].clr(); dp[0].push(0, 1);
	for(int i = 1; i <= n; i++) {
		cur ^= 1;
		dp[cur].clr();
        for(int j = 0; j < dp[cur^1].sz; j++) {
            dp[cur].push(dp[cur^1].sta[j] << 2, dp[cur^1].val[j]);
        }
		for(int j = 1; j <= m; j++) {
			cur ^= 1; dp[cur].clr();
			for(int k = 0; k < dp[cur^1].sz; k++) {
				int L = getbit(dp[cur^1].sta[k], j-1);
				int U = getbit(dp[cur^1].sta[k], j);
				int s = clrbit(dp[cur^1].sta[k], j-1, j);
				//PF("* %d %d %d\n", L, U, s);
				if(!L && !U) {
					if(!M[i][j]) dp[cur].push(s, dp[cur^1].val[k]);
					else if(i < n && j < m && M[i+1][j] && M[i][j+1])
						dp[cur].push(s|BIT(1, j-1)|BIT(2, j), dp[cur^1].val[k]);
				}
				else if(!L || !U) {
					int dir = L ? L : U;
					if(i < n && M[i+1][j]) dp[cur].push(s|BIT(dir, j-1), dp[cur^1].val[k]);
					if(j < m && M[i][j+1]) dp[cur].push(s|BIT(dir, j), dp[cur^1].val[k]);
				}
				else if(L == 1 && U == 1) 
					dp[cur].push(s^BIT(3, FindR(s, j)), dp[cur^1].val[k]);
				else if(L == 2 && U == 2)
					dp[cur].push(s^BIT(3, FindL(s, j-1)), dp[cur^1].val[k]);
				else if(L == 2 && U == 1)
					dp[cur].push(s, dp[cur^1].val[k]);
				else if(i == ex && j == ey)
					dp[cur].push(s, dp[cur^1].val[k]);
			}
		}
	}
	for(int i = 0; i < dp[cur].sz; i++)
		if(!dp[cur].sta[i]) return dp[cur].val[i];
	return 0;
}
int main() {
	char ch;
	SF("%d%d", &n, &m);
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= m; j++) {
			SF(" %c", &ch); 
			if(ch == '*') M[i][j] = 0;
			else M[i][j] = 1, ex = i, ey = j;
		}
	LL ans = solve();
	cout << ans;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值