隐藏
「bsoj2842」Formula 2 - 插头DP | Bill Yang's Blog

路终会有尽头,但视野总能看到更远的地方。

0%

「bsoj2842」Formula 2 - 插头DP

题目大意

    给你一个$N*M$的棋盘,问有多少条路径使得经过每个格子恰好一次,起点和终点任意。$2\le N,M\le9$。


题目分析

上题的不同在于本题不需要形成回路,这样括号的匹配性质就被打乱了。注意到通路只有两个独立的地方,故引入新状态独立插头。

设状态$3$表示独立插头,这样我们就有了四种状态。

在上题的基础上:

我们需要加入额外的转移:

注意判断状态的合法性:不越出边界、插头始终小于两个。


代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;

typedef long long LL;

inline const int Get_Int() {
int num=0,bj=1;
char x=getchar();
while(x<'0'||x>'9') {
if(x=='-')bj=-1;
x=getchar();
}
while(x>='0'&&x<='9') {
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}

const int mod=60007;

int n,m,now,Hash[mod],cnt[2],status[2][20005];
LL ans=0,f[2][20005];

#define bit(x) ((x)<<1)

void trans(int s,LL sum) {
int pos=s%mod;
while(Hash[pos]) { //找空位
if(status[now][Hash[pos]]==s) {
f[now][Hash[pos]]+=sum;
return;
}
pos=(pos+1)%mod;
}
Hash[pos]=++cnt[now];
status[now][Hash[pos]]=s;
f[now][Hash[pos]]=sum;
}

int Find_After(int s,int x) {
int delta=1;
for(int i=x+1; i<=m; i++) {
int val=(s>>bit(i))&3;
if(val==1)delta++;
if(val==2)delta--;
if(!delta)return i;
}
}

int Find_Pre(int s,int x) {
int delta=1;
for(int i=x-1; i>=0; i--) {
int val=(s>>bit(i))&3;
if(val==2)delta++;
if(val==1)delta--;
if(!delta)return i;
}
}

int main() {
n=Get_Int();
m=Get_Int();
f[0][1]=cnt[0]=1;
status[0][1]=0;
now=0;
for(int i=1; i<=n; i++) {
for(int j=1; j<=m; j++) {
now^=1;
cnt[now]=0;
memset(Hash,0,sizeof(Hash));
for(int k=1; k<=cnt[now^1]; k++) {
int s=status[now^1][k],l=(s>>bit(j-1))&3,r=(s>>bit(j))&3,indep=0;
LL last=f[now^1][k];
for(int x=0; x<=m; x++)
if(((s>>bit(x))&3)==3)indep++;
if(l==0&&r==0) {
if(i<n&&j<m)trans(s^(1<<bit(j-1))^(2<<bit(j)),last);
if(i<n&&indep<2)trans(s^(3<<bit(j-1)),last);
if(j<m&&indep<2)trans(s^(3<<bit(j)),last);
} else if(l==1&&r==0) {
if(j<m)trans(s^(1<<bit(j-1))^(1<<bit(j)),last);
if(i<n)trans(s,last);
int pos=Find_After(s,j-1);
if(indep<2)trans(s^(2<<bit(pos))^(3<<bit(pos))^(1<<bit(j-1)),last);
} else if(l==2&&r==0) {
if(j<m)trans(s^(2<<bit(j-1))^(2<<bit(j)),last);
if(i<n)trans(s,last);
int pos=Find_Pre(s,j-1);
if(indep<2)trans(s^(1<<bit(pos))^(3<<bit(pos))^(2<<bit(j-1)),last);
} else if(l==0&&r==1) {
if(i<n)trans(s^(1<<bit(j))^(1<<bit(j-1)),last);
if(j<m)trans(s,last);
int pos=Find_After(s,j);
if(indep<2)trans(s^(2<<bit(pos))^(3<<bit(pos))^(1<<bit(j)),last);
} else if(l==0&&r==2) {
if(i<n)trans(s^(2<<bit(j))^(2<<bit(j-1)),last);
if(j<m)trans(s,last);
int pos=Find_Pre(s,j);
if(indep<2)trans(s^(1<<bit(pos))^(3<<bit(pos))^(2<<bit(j)),last);
} else if(l==3&&r==0) {
if(j<m)trans(s^(3<<bit(j-1))^(3<<bit(j)),last);
if(i<n)trans(s,last);
if(i==n&&j==m)ans+=last;
} else if(l==0&&r==3) {
if(i<n)trans(s^(3<<bit(j))^(3<<bit(j-1)),last);
if(j<m)trans(s,last);
if(i==n&&j==m)ans+=last;
} else if(l==1&&r==1) {
int pos=Find_After(s,j);
trans(s^(2<<bit(pos))^(1<<bit(pos))^(1<<bit(j-1))^(1<<bit(j)),last);
} else if(l==2&&r==2) {
int pos=Find_Pre(s,j-1);
trans(s^(1<<bit(pos))^(2<<bit(pos))^(2<<bit(j-1))^(2<<bit(j)),last);
} else if(l==3&&r==1) {
int pos=Find_After(s,j);
trans(s^(2<<bit(pos))^(3<<bit(pos))^(3<<bit(j-1))^(1<<bit(j)),last);
} else if(l==3&&r==2) {
int pos=Find_Pre(s,j);
trans(s^(1<<bit(pos))^(3<<bit(pos))^(3<<bit(j-1))^(2<<bit(j)),last);
} else if(l==1&&r==3) {
int pos=Find_After(s,j-1);
trans(s^(2<<bit(pos))^(3<<bit(pos))^(1<<bit(j-1))^(3<<bit(j)),last);
} else if(l==2&&r==3) {
int pos=Find_Pre(s,j-1);
trans(s^(1<<bit(pos))^(3<<bit(pos))^(2<<bit(j-1))^(3<<bit(j)),last);
} else if(l==2&&r==1)trans(s^(2<<bit(j-1))^(1<<bit(j)),last);
else if(l==3&&r==3&&i==n&&j==m)ans+=last;
}
}
for(int j=1; j<=cnt[now]; j++)status[now][j]<<=2;
}
printf("%lld\n",ans);
return 0;
}
姥爷们赏瓶冰阔落吧~