求助P5056
查看原帖
求助P5056
197493
unputdownable楼主2020/6/6 14:57

新手新学插头DP,写炸

其中#9跑出来是负的..

已经和题解对照过几遍了(很可能哪里还没写好)

求助

//新手第一次打插头DP,参考了题解 (@y2823774827y 的)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=13;
const int mod=300017;
const int L=33554432;
int n,m,endx,endy,now,lst,ans;
int a[N][N],pow2[N+1],que[2][L],val[2][L],head[300055],next[L],cnt[2];
inline void read(int &x) {
	int tmp_read=0,nega=1;
	char c=getchar();
	while(c<'0'||c>'9') {
		if(c=='-')nega=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9') {
		tmp_read=tmp_read*10+c-'0';
		c=getchar();
	}
	x=tmp_read*nega;
	return ;
}
inline void ins(int bit,int v) {
	int u=bit%mod;
	for(register int i=head[u]; i!=0; i=next[i])
		if(que[now][i]==bit) {
			val[now][i]+=v;
			return ;
		}
	++cnt[now];
	next[cnt[now]]=head[u];
	head[u]=cnt[now];
	que[now][head[u]]=bit;
	val[now][head[u]]=v;
	return ;
}
signed main() {
//读入
	read(n),read(m);
//	scanf("%lld %lld",&n,&m);
	char cr=getchar();
	for(register int i=1; i<=n; ++i) {
		while(cr!='.'&&cr!='*')
			cr=getchar();
		for(register int u=1; u<=m; ++u) {
			if(cr=='.') {
				a[i][u]=1;
				endx=i,endy=u;
			}
			cr=getchar();
		}
	}
//初始化
	pow2[0]=1;
	for(register int i=1; i<=N; ++i)
		pow2[i]=pow2[i-1]<<2;
//	cnt[0]=1;
//	que[0][1]=0;
//	val[0][1]=1;
	ins(0,1);
//DP
	for(register int i=1; i<=n; ++i) {
		for(register int u=1; u<=cnt[now]; ++u)
			que[now][u]<<=2;
		for(register int u=1; u<=m; ++u) {
			//清空历史数据
			lst=now;
			now^=1;
			for(register int k=0; k<=300017; ++k) head[k]=0;
			cnt[now]=0;
			//DP
			for(register int k=1; k<=cnt[lst]; ++k) {
				int bit=que[lst][k];
				int num=val[lst][k];
				int ri=(bit>>((u-1)*2))%4,up=(bit>>(u*2))%4;
//				cout<<i<<' '<<u<<' '<<bit<<' '<<num<<endl;
				if(!a[i][u]) { //是障碍
					if(!ri&&!up)
						ins(bit,num);
				} else {
					if(!ri&&!up) {
						if(a[i+1][u]&&a[i][u+1])
							ins(bit+pow2[u-1]+pow2[u]*2,num);
					} else if(!ri&&up) {
						if(a[i+1][u])
							ins(bit-up*pow2[u]+up*pow2[u-1],num);
						if(a[i][u+1])
							ins(bit,num);
					} else if(ri&&!up) {
						if(a[i+1][u])
							ins(bit,num);
						if(a[i][u+1])
							ins(bit-ri*pow2[u-1]+ri*pow2[u],num);
					}  else {//两个要连起来
						if(ri==1&&up==1) { //改右边的插头
							int _change=1;
							for(int o=u+1; o<=m; ++o) {
								if((bit>>(o*2))%4==1)
									++_change;
								if((bit>>(o*2))%4==2)
									--_change;
								if(!_change) {
									ins(bit-pow2[u]-pow2[u-1]-pow2[o],num);//二改一
									break;
								}
							}
						} else if(ri==2&&up==2) { //改左边的插头
							int _change=1;
							for(int o=u-2; o>=0; --o) {
								if((bit>>(o*2))%4==1)
									--_change;
								if((bit>>(o*2))%4==2)
									++_change;
								if(!_change) {
									ins(bit-(pow2[u]*2)-(pow2[u-1]*2)+pow2[o],num);//一改二
									break;
								}
							}
						} else if(ri==2&&up==1) { //没有插头
							ins(bit-(pow2[u-1]*2)-pow2[u],num);
						} else if(i==endx&&u==endy) { //ri==1&&up==2 只能在终点成立
//							cout<<"~~~"<<num<<endl;
							ans+=num;
						}
					}
				}
			}
		}
	}
	printf("%lld\n",ans);
	return 0;
}

2020/6/6 14:57
加载中...