题面

大秦为你打开题目传送门

题目描述

小朋友要玩,卡卡颂。

在开始游戏之前他们要拼地图,有 $n$ 行 $m$ 列的格子,每个格子上有一个小方块,每个小方块的四条边可能是城市 $(C)$ ,道路 $(R)$ 或者空地 $(F)$ 。现在要求旋转这些小方块,使得相邻的小方块对应的边上是相同的建筑。

问有多少种旋转方案,不准对方块翻转,不准交换方块的位置。

思路

这题也是直接一眼轮廓线DP,直接处理出所有方块旋转以后的值,然后处理出这个轮廓线边缘的所有值,由于三进制的计算十分的复杂,我这里就直接用了字符串来处理。我用 $1$ ~ $m$ 表示这个轮廓线的底边的值,再用 $m + 1$ 表示这个轮廓线突出来能看到的这个右边的边(如下图)

这样就简单了,直接递归做就可以了,算是一个非常玄学的代码了,,

代码

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
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef __int128 int128;

namespace FastIO
{
// char buf[1 << 20], *p1, *p2;
// #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 20, stdin), p1 == p2) ? EOF : *p1++)
template<typename T> inline T read(T& x) {
x = 0;
int f = 1;
char ch;
while (!isdigit(ch = getchar())) if (ch == '-') f = -1;
while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
x *= f;
return x;
}
template<typename T, typename... Args> inline void read(T& x, Args &...x_) {
read(x);
read(x_...);
return;
}
inline ll read() {
ll x;
read(x);
return x;
}
};
using namespace FastIO;

const int P = 1e9 + 7;

struct Cube{
char lt , rt , dw , up;
Cube(char a = 'A' , char b = 'A' , char c = 'A' , char d = 'A'){
up = a , dw = b , lt = c , rt = d;
}
};

int n, m;
Cube a[20][20][4];

map<string , ll> dp[20][20];

inline void Input(){
read(n, m);
char s[5];
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
scanf("%s", s);
a[i][j][0].up = s[0];
a[i][j][0].rt = s[1];
a[i][j][0].dw = s[2];
a[i][j][0].lt = s[3];
}
}
}

inline ll DP(int i , int j , string mask){
if(i > n) return 1;
if(dp[i][j].find(mask) != dp[i][j].end()) return dp[i][j][mask];
ll ans = 0;
for(int k = 0; k < 4; k++){
if((a[i][j][k].up == mask[j] || i == 1) && (a[i][j][k].lt == mask[m + 1] || j == 1)){
string ts = mask;
ts[m + 1] = a[i][j][k].rt;
ts[j] = a[i][j][k].dw;
if(j+1 <= m) ans = (ans + DP(i, j + 1 , ts)) % P;
else ans = (ans + DP(i + 1 , 1 , ts)) % P;
}
}
return dp[i][j][mask] = ans % P;
}

inline void Work(){
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
for(int k = 1; k < 4; k++){
a[i][j][k].up = a[i][j][k-1].lt;
a[i][j][k].rt = a[i][j][k-1].up;
a[i][j][k].dw = a[i][j][k-1].rt;
a[i][j][k].lt = a[i][j][k-1].dw;
}
}
}
string s = " ";
for(int i = 1; i <= m + 1; i++) s += 'A';
printf("%lld\n" , DP(1, 1, s) % P);
}

int main(){
int T = 1;
while(T--) {
Input();
Work();
}
return 0;
}