P4401 [IOI2007]Miners 矿工配餐 DP

P4401 [IOI2007]Miners 矿工配餐 DP

题目链接

​ 大力DP即可.

​ \(f[x][a_1][a_2][b_1][b_2]\)表示到第\(x\)天, 第一个矿洞前两天的饭是\(a_1, a_2\), 第二个矿洞前两天的饭是\(b_1, b_2\).

​ 转移 : \(f[x+1][a2][t][b1][b2] = max(f[x+1][a2][t][b1][b2], f[x][a1][a2][b1][b2] + tmp)\),

​ \(f[x+1][a1][a2][b2][t] = max(f[x+1][a1][a2][b2][t], f[x][a1][a2][b1][b2] + tmp)\);

​ 这两个方程分别表示把第\(x + 1\)天的饭给了\(1\)矿洞, \(2\)矿洞, 然后我们可以根据这三天的饭的情况算出产煤量\(tmp\).

​ 因为这个题卡空间, 所以第一位要滚掉.

#include <bits/stdc++.h>

using namespace std;

inline long long read() {
	long long s = 0, f = 1; char ch;
	while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
	for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
	return s * f;
}

int n, ans;
char ch[100005];
int f[2][4][4][4][4];

int calc(int x, int y, int z) {
	int res = 1;
	if(x != 0 && x != y && x != z) res ++;
	if(y != 0 && y != z) res ++;
	return res;
}

int main() {
	
	n = read(); cin >> ch;
	memset(f, -1, sizeof(f)); f[0][0][0][0][0] = 0;
	for(int i = 0;i < n; i++) {
		int x = i % 2, y = (i + 1) % 2;
		for(int a1 = 0;a1 <= 3; a1++) {
			for(int a2 = 0;a2 <= 3; a2++) {
				for(int b1 = 0;b1 <= 3; b1++) {
					for(int b2 = 0;b2 <= 3; b2++) {
						if(f[x][a1][a2][b1][b2] == -1) continue ;
						int t = ch[i] == 'M' ? 1 : ch[i] == 'B' ? 2 : 3; 
						int tmp = calc(a1, a2, t);
						f[y][a2][t][b1][b2] = max(f[y][a2][t][b1][b2], f[x][a1][a2][b1][b2] + tmp);
						tmp = calc(b1, b2, t);
						f[y][a1][a2][b2][t] = max(f[y][a1][a2][b2][t], f[x][a1][a2][b1][b2] + tmp);
					}
				}
			}
		}
	}
	for(int a1 = 0;a1 <= 3; a1++) for(int a2 = 0;a2 <= 3; a2++)
		for(int b1 = 0;b1 <= 3; b1++) for(int b2 = 0;b2 <= 3; b2++) ans = max(ans, f[n % 2][a1][a2][b1][b2]);
	printf("%d", ans);

	return 0;
}
上一篇:逆向查询,这些招数会了吗?


下一篇:设计模式-观察者模式(Observer Model)