之前学的全忘了,到头来又要重炒一遍板子,不过因为码力增强(认真抄),感觉思路清晰一点了。
邮递员:
放个注释的板子
1 #include<cstdio>
2 #include<iostream>
3 #include<cstdlib>
4 #include<cstring>
5 #define LL __int128
6 using namespace std;
7 int n,m;
8 LL ans=0;
9 struct HASH_MAP{
10 #define mo 2601
11 struct nnode{
12 int nt,key;
13 LL val;
14 }e[mo*20];int hd[mo],itot;
15 void init(){
16 itot=0;
17 memset(hd,0,sizeof(hd));
18 return ;
19 }
20 LL &operator [](const int &key){
21 const int u=key%mo;
22 for(int i=hd[u];i;i=e[i].nt)
23 if(e[i].key==key)return e[i].val;
24 e[++itot].key=key,e[itot].val=0;
25 e[itot].nt=hd[u],hd[u]=itot;
26 return e[itot].val;
27 }
28 }f[2];
29 int now=1,past=0;
30 inline int Find(int sta,int pos){
31 return (sta>>((pos-1)<<1))&3;
32 }//四进制取位
33 inline void Set(int &sta,int pos,int w){
34 sta-=(Find(sta,pos)<<((pos-1)<<1));
35 sta+=w<<((pos-1)<<1);
36 return ;
37 }//四进制位赋值
38 //0无插头 1左括号插头 2右括号插头
39 inline int Get(int sta,int pos){
40 int knd=Find(sta,pos);
41 if(knd==0)return pos;
42 //自己是自己来省掉无插头
43 int cnt=0;
44 if(knd==1){//左括号往右找
45 for(int i=pos,tmp;i<=m+1;++i){
46 tmp=Find(sta,i);
47 if(tmp==1)++cnt;
48 if(tmp==2)--cnt;
49 if(cnt==0)return i;
50 }
51 }
52 else{
53 for(int i=pos,tmp;i>=1;--i){
54 tmp=Find(sta,i);
55 if(tmp==1)++cnt;
56 if(tmp==2)--cnt;
57 if(cnt==0)return i;
58 }
59 }
60 return -1;
61 }//查找对应的插头,即括号匹配
62 void wk(int x,int y){//将轮廓线扩过这个格子
63 int lim=f[past].itot;
64 f[now].init();
65 for(int i=1;i<=lim;++i){
66 int sta=f[past].e[i].key;
67 LL val=f[past].e[i].val;
68 int p1=Find(sta,y),p2=Find(sta,y+1);
69 //左边的格子的插头,上边格子的插头
70 int g1=Get(sta,y),g2=Get(sta,y+1);
71 if(g1==-1||g2==-1)//没有对应插头,不合法
72 continue;
73 if(!p1&&!p2){//新建两个插头
74 if(x!=n&&y!=m){
75 Set(sta,y,1);
76 Set(sta,y+1,2);
77 f[now][sta]+=val;
78 }
79 }
80 else if(!p1&&p2){//要么向下,要么向右
81 if(y!=m)f[now][sta]+=val;
82 if(x!=n){
83 Set(sta,y,p2);
84 Set(sta,y+1,0);
85 f[now][sta]+=val;
86 }
87 }
88 else if(p1&&!p2){//同上
89 if(x!=n)f[now][sta]+=val;
90 if(y!=m){
91 Set(sta,y,0);
92 Set(sta,y+1,p1);
93 f[now][sta]+=val;
94 }
95 }
96 else if(p1==1&&p2==1){//交换p2和p2对应插头的类型,使p1和p2能拼在一起
97 Set(sta,g2,1);
98 Set(sta,y,0);
99 Set(sta,y+1,0);
100 f[now][sta]+=val;
101 }
102 else if(p1==2&&p2==2){//同上
103 Set(sta,g1,2);
104 Set(sta,y,0);
105 Set(sta,y+1,0);
106 f[now][sta]+=val;
107 }
108 else if(p1==1&&p2==2){
109 if(x==n&&y==m)
110 ans+=val;
111 }
112 else if(p1==2&&p2==1){//交换p1和p2的类型
113 Set(sta,y,0);
114 Set(sta,y+1,0);
115 f[now][sta]+=val;
116 }
117 }
118 now=past,past^=1;
119 return ;
120 }
121 void pt(LL x){
122 if(!x)return ;
123 pt(x/10);
124 putchar(x%10+'0');
125 return ;
126 }
127 int main(){
128 //freopen("da.in","r",stdin);
129
130 cin>>n>>m;
131 if(n==1||m==1)puts("1"),exit(0);
132 if(m>n)m^=n,n^=m,m^=n;
133 f[0].init();f[1].init();
134 f[0][0]=1;
135 for(int i=1;i<=n;++i){
136 for(int j=1;j<=m;++j)wk(i,j);
137 if(i!=n){
138 int lim=f[past].itot;
139 for(int j=1;j<=lim;++j)
140 f[past].e[j].key<<=2;
141 //转到下一行,多一个位表示新增的墙角
142 }
143 }
144 ans+=ans;
145 //cout<<ans<<endl;
146 if(!ans)puts("0"),exit(0);
147 pt(ans);
148
149 return 0;
150 }
151 //工业化代码应该还是好调一些的
152 //ladylex学长的板子
153 //之前打的板子已经不会了
来源:https://www.cnblogs.com/2018hzoicyf/p/12021757.html