[JOI2018] Dango Maker 题解

Description

link

Solution

如果两个团子重合肯定是下面三种情况:

1
2
3
  R          RGW          R
G G RGW
RGW W W

我们会发现两个重合团子的 G 一定是在从右上到左下的对角线上的,且距离小于等于 11。根据这个性质就可以发现任意两个对角线上的团子肯定互不影响,那么对于每一个对角线进行 dp 即可。

其中 f[i][0/1/2]f[i][0/1/2] 表示当前对角线上前 ii 行,第 ii 行的团子 不放/横放/竖放 的最大团子数,依次递推即可。

时间复杂度:O(nm)O(nm),吊打二分图。

Code

代码
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
#include <bits/stdc++.h>

#ifdef ORZXKR
#include <debug.h>
#else
#define debug(...) 1
#endif

#define file(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)

using namespace std;

int read() {
int x = 0, f = 0; char ch = getchar();
while (ch < '0' || ch > '9') f |= ch == '-', ch = getchar();
while (ch >= '0' && ch <= '9') x = (x * 10) + (ch ^ 48), ch = getchar();
return f ? -x : x;
}

const int kMaxN = 3005;

int n, m, ans;
int f[kMaxN][3]; // 0/1/2 : 不放/横放/竖放
char s[kMaxN][kMaxN];

int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) {
scanf("%s", s[i] + 1);
}
for (int sm = 2; sm <= n + m; ++sm) {
memset(f, 0, sizeof(f));
int tmp = 0;
for (int i = max(1, sm - m), j = sm - i; i <= n && j; ++i, --j) {
f[i][0] = max({f[i - 1][0], f[i - 1][1], f[i - 1][2]});
if (s[i][j] == 'G') {
if (s[i - 1][j] == 'R' && s[i + 1][j] == 'W')
f[i][1] = max(f[i][1], max(f[i - 1][0], f[i - 1][1]) + 1);
if (s[i][j - 1] == 'R' && s[i][j + 1] == 'W')
f[i][2] = max(f[i][2], max(f[i - 1][0], f[i - 1][2]) + 1);
}
tmp = max(tmp, max({f[i][0], f[i][1], f[i][2]}));
}
ans += tmp;
}
printf("%d\n", ans);
return 0;
}

[JOI2018] Dango Maker 题解
https://sobaliuziao.github.io/2022/10/07/post/69d1d5f8.html
作者
Egg_laying_master
发布于
2022年10月7日
许可协议