#2099. 「CQOI2015」標識設計(插頭dp)
阿新 • • 發佈:2020-08-13
題目描述
題解
第一次寫插頭dp
求哈密頓迴路:https://blog.csdn.net/litble/article/details/79369147,本質是維護輪廓線+左右括號序列
本題只需要維護下/右插頭即可,狀態數是C(m,3)級別的,壓一壓即可
code
#include <bits/stdc++.h> #define fo(a,b,c) for (a=b; a<=c; a++) #define fd(a,b,c) for (a=b; a>=c; a--) #define ll long long //#define file using namespace std; ll f[4527][4][2],g[4527][4][2],ans; int num[31][31][31],b[4527][3],n,m,i,j,k,l,tot,I[3]; bool bz[31][31]; char ch; void swap(int &x,int &y) {int z=x;x=y;y=z;} int main() { #ifdef file freopen("loj2099.in","r",stdin); #endif scanf("%d%d",&n,&m); fo(i,1,n) { fo(j,1,m) { ch=getchar(); while (ch!='.' && ch!='#') ch=getchar(); bz[i][j]=ch=='#'; } } tot=1;num[0][0][0]=1;b[1][0]=0,b[1][1]=0,b[1][2]=0; fo(i,1,m) { num[i][0][0]=++tot; b[tot][0]=i,b[tot][1]=0,b[tot][2]=0; fo(j,1,i-1) { num[i][j][0]=++tot; b[tot][0]=i,b[tot][1]=j,b[tot][2]=0; fo(k,1,j-1) num[i][j][k]=++tot,b[tot][0]=i,b[tot][1]=j,b[tot][2]=k; } } f[1][0][0]=1; fo(i,1,n) { fo(j,0,m-1) { memset(g,0,sizeof(g)); fo(k,1,tot) { fo(l,0,3) { if (!bz[i][j+1]) { I[0]=b[k][0],I[1]=b[k][1],I[2]=b[k][2]; if (I[0]==j+1) g[num[I[1]][I[2]][0]][l][1]+=f[k][l][0]; else if (I[1]==j+1) g[num[I[0]][I[2]][0]][l][1]+=f[k][l][0]; else if (I[2]==j+1) g[num[I[0]][I[1]][0]][l][1]+=f[k][l][0]; else if (l<3) { I[2]=j+1; if (I[2]>I[1]) swap(I[1],I[2]); if (I[1]>I[0]) swap(I[0],I[1]); g[num[I[0]][I[1]][I[2]]][l+1][0]+=f[k][l][0]; } if (b[k][0]!=j+1 && b[k][1]!=j+1 && b[k][2]!=j+1) { g[k][l][0]+=f[k][l][1]; g[k][l][1]+=f[k][l][1]; } } if (!bz[i][j+1] || (b[k][0]!=j+1 && b[k][1]!=j+1 && b[k][2]!=j+1)) g[k][l][0]+=f[k][l][0]; } } memcpy(f,g,sizeof(f)); } if (i<n) { fo(k,1,tot) { fo(l,0,3) f[k][l][1]=0; } } } printf("%lld\n",f[1][3][0]); fclose(stdin); fclose(stdout); return 0; }