[COGS 1512][URAL 1519]一级方程式赛车

按格插头DP



#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 25
using namespace std;

typedef long long ll;
int n, m, Endx, Endy;
const int mod = 997;
const int N = 1000010;
struct hashmap{
	int h[mod],nxt[N],size;
	ll f[N],st[N];
	void init(){
		memset(h, 0, sizeof h);
		size = 0;
	}
	void push(ll val,ll ans){
		int now = val % mod;
		for(int i = h[now]; i;i = nxt[i])
		    if(st[i] == val){
                f[i] += ans;
				return;
		    }
		++size;
		f[size] = ans;
		st[size] = val;
		nxt[size] = h[now];
		h[now] = size;
	}
}dp[2];
bool map[maxn][maxn];
int code[maxn], ch[maxn];
void Decode(ll st){
	for(int i = m;i >= 0;i --){
		code[i] = st & 7;
		st >>= 3;
	}
}
ll Encode(){
	ll st = 0;
	int cnt = 0;
	memset(ch, -1, sizeof ch);
	ch[0] = 0;
	for(int i = 0;i <= m;i ++){
		if(ch[code[i]] == -1)
		    ch[code[i]] = ++cnt;
		code[i] = ch[code[i]];
		st <<= 3;
		st |= code[i];
	}
	return st;
}
void Shift(){
	for(int i = m;i > 0;i --)
	    code[i] = code[i - 1];
	code[0] = 0;
}

void DP(int i, int j, int cur, bool type){
	if(type == 0){
		for(int k = 1;k <= dp[cur].size;k ++){
			Decode(dp[cur].st[k]);
			code[j] = code[j - 1] = 0;
			if(j == m)Shift();
			dp[cur ^ 1].push(Encode(), dp[cur].f[k]);
		}
		return;
	}
	for(int k = 1;k <= dp[cur].size;k ++){
		Decode(dp[cur].st[k]);

		int Left = code[j - 1],Up = code[j];
		if(Left && Up){
			if(Left == Up){
				if(Endx == i && Endy == j){
					code[j] = code[j - 1] = 0;
					if(j == m)Shift();
					dp[cur ^ 1].push(Encode(),dp[cur].f[k]);
				}
			}
			else{
				code[j] = code[j - 1] = 0;
				for(int i = 0;i <= m;i ++)
				    if(code[i] == Up)
				        code[i] = Left;
				if(j == m)Shift();
				dp[cur ^ 1].push(Encode(),dp[cur].f[k]);
			}
		}
		else if((Left == 0 && Up)||(Up == 0 && Left)){
			int tmp = Left == 0 ? Up : Left;
			if(map[i][j + 1]){
				code[j - 1] = 0;
				code[j] = tmp;
				if(j == m)Shift();
				dp[cur ^ 1].push(Encode(),dp[cur].f[k]);
			}
			if(map[i + 1][j]){
				code[j - 1] = tmp;
				code[j] = 0;
				if(j == m)Shift();
				dp[cur ^ 1].push(Encode(),dp[cur].f[k]);
			}
		}
		else{
			if(map[i][j + 1] && map[i + 1][j]){
				code[j - 1] = code[j] = 15;
				dp[cur ^ 1].push(Encode(),dp[cur].f[k]);
			}
		}
	}
}
int main(){
	freopen("formula1.in", "r", stdin);
	freopen("formula1.out", "w", stdout);
	scanf("%d%d", &n, &m);
	for(int i = 1;i <= n;i ++)
		for(int j = 1;j <= m;j ++){
			char QAQ = getchar();
			for(;QAQ < '!';QAQ = getchar());
			if(QAQ == '.'){
				map[i][j] = true;
				Endx = i;
				Endy = j;
			}
		}

	if(Endx == 0){
		printf("0\n");
		return 0;
	}
	int cur = 0;
	ll ans = 0;
	dp[cur].init();
	dp[cur].push(0, 1);
	for(int i = 1;i <= n;i ++)
	    for(int j = 1;j <= m;j ++){
			dp[cur ^ 1].init();
	        DP(i, j, cur, map[i][j]);
	        cur ^= 1;
	    }

	for(int i = 1;i <= dp[cur].size;i ++)
	    ans += dp[cur].f[i];
	printf("%lld\n",ans);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值