1. 程式人生 > 實用技巧 >「JOI 2018 Final」糰子製作

「JOI 2018 Final」糰子製作

一個糰子可能被從兩個方向選取,但只能保留一個方向,相同取向的方案之間不會影響,這形成了個二分圖,在不能同時選的方案之間連邊,
答案就是最大獨立集,但邊數太多,會 \(T\)。但很多方案之間是獨立的,確切來說只有中間點在同一斜線上的方案才可能矛盾,
於是可以對每個斜線上進行 \(dp\) 即可。

#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i = (a); i <= (b); i++)
#define per(i, a, b) for (int i = (a); i >= (b); i--)
#define fi first
#define se second
const int N = 3005, inf = 0x3f3f3f3f, mod = 1e9 + 7;
typedef pair <int, int> P;
typedef long long LL;

int n, m, ans, f[N][3];
char a[N][N];

bool chk_(int x, int y, int op) {
	if (op == 1) 
		return a[x][y + 1] == 'W' && a[x][y - 1] == 'R';
	else
		return a[x - 1][y] == 'R' && a[x + 1][y] == 'W';
}

int main() {
//	freopen("data.in", "r", stdin);
	scanf("%d%d", &n, &m);
	rep (i, 1, n)
		scanf("%s", a[i] + 1);
	rep (xy, 2, n + m) {
		int lx = max(1, xy - m), rx = min(xy, n);
		f[lx - 1][0] = 0, f[lx - 1][1] = f[lx - 1][2] = -inf;
		rep (x, lx, rx) {
			int y = xy - x;
			f[x][0] = max(f[x - 1][0], max(f[x - 1][1], f[x - 1][2])), f[x][1] = f[x][2] = -inf;
			if (a[x][y] != 'G') 
				continue;
			if (chk_(x, y, 1))
				f[x][1] = max(f[x - 1][1], f[x - 1][0]) + 1;
			if (chk_(x, y, 2))
				f[x][2] = max(f[x - 1][2], f[x - 1][0]) + 1;
		}
		ans += max(f[rx][0], max(f[rx][1], f[rx][2]));
	}
	printf("%d\n", ans);
	return 0;
}