【Ural1519】— Formula1(轮廓线dp)

传送门

看这个大佬的博客吧,讲的很详细:传送门

#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
#define ll long long
#define gc getchar
inline int read(){
	char ch=gc();
	int res=0,f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
	return f?res:-res;
}
const int M=300005;
const int N=15;
int n,m,cnt,idx,mp[N][N],tot[2],bit[N],ex,ey;
int adj[M],nxt[M],to[M];
ll f[2][M],sta[2][M],ans;
char s[N];
inline void calc(ll s,ll num){
	int u=s%M;
	for(int e=adj[u];e;e=nxt[e]){
		if(sta[idx][to[e]]==s){
			f[idx][to[e]]+=num;return;
		}
	}
	++tot[idx];
	sta[idx][tot[idx]]=s;
	f[idx][tot[idx]]=num;
	nxt[++cnt]=adj[u];
	adj[u]=cnt,to[cnt]=tot[idx];
}
int main(){
	for(int i=0;i<N;i++)bit[i]=i<<1;
	tot[idx]=1,f[idx][1]=1;
	n=read(),m=read();
	for(int i=1;i<=n;i++){
		scanf("%s",s+1);
		for(int j=1;j<=m;j++){
			mp[i][j]=(s[j]=='.');
			if(s[j]=='.')ex=i,ey=j;
		}
	}
	for(int i=1;i<=n;i++){
		for(int k=1;k<=tot[idx];k++)sta[idx][k]<<=2;
		for(int j=1;j<=m;j++){
			memset(adj,0,sizeof(adj));
			cnt=0,idx^=1;
			tot[idx]=0;
			for(int k=1;k<=tot[idx^1];k++){
				ll s=sta[idx^1][k];
				ll num=f[idx^1][k];
				int p=(s>>bit[j-1])%4;
				int q=(s>>bit[j])%4;
				if(!mp[i][j]){
					if(p+q==0)calc(s,num);
				}
				else if(p+q==0){
					if(!mp[i+1][j]||!mp[i][j+1])continue;
					s=s+(1<<bit[j-1])+2*(1<<bit[j]);
					calc(s,num);
				}
				else if(!p&&q){
					if(mp[i][j+1])calc(s,num);
					if(mp[i+1][j]){
						s=s+q*(1<<bit[j-1])-q*(1<<bit[j]);
						calc(s,num);
					}
				}
				else if(p&&!q){
					if(mp[i+1][j])calc(s,num);
					if(mp[i][j+1]){
						s=s-p*(1<<bit[j-1])+p*(1<<bit[j]);
						calc(s,num);
					}
				}
				else if(p+q==2){
					int b=1;
					for(int t=j+1;t<=m;t++){
						int v=(s>>bit[t])%4;
						if(v==1)b++;
						if(v==2)b--;
						if(!b){
							s=s-(1<<bit[t]);
							break;
						}
					}
					s=s-(1<<bit[j-1])-(1<<bit[j]);
					calc(s,num);
				}
				else if(p+q==4){
					int b=1;
					for(int t=j-2;t;t--){
						int v=(s>>bit[t])%4;
						if(v==2)b++;
						if(v==1)b--;
						if(!b){
							s=s+(1<<bit[t]);
							break;
						}
					}
					s=s-2*(1<<bit[j-1])-2*(1<<bit[j]);
					calc(s,num);
				}
				else if(p==1&&q==2){
					if(i==ex&&j==ey)ans+=num;
				}
				else if(p==2&&q==1){
					s=s-2*(1<<bit[j-1])-(1<<bit[j]);
					calc(s,num);
				}
			}
		}
	}
	cout<<ans;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值