P2585 [ZJOI2006]三色二叉树-Solution

经典区间dp

思路:

每到了序列的一个位置,这个位置的数字就表示他有几个儿子,向下搜索0/1/2次

设状态:
dp[i][j] 表示i这个节点,有j个儿子,最多有多少绿点

f[i][j] 表示i节点,有j个儿子,最少有几个绿点

在搜索的同时将三种情况都顺便转移一下。

BOOM!!
/**
 *	author: zcxxxxx
 *	creater: 2022.6.1
**/
#include <bits/stdc++.h>
#define il inline
#define reg register
#define ll long long
#define pii pair<int, int>
using namespace std;
const int A = 1e2 + 7;
const int B = 1e3 + 7;
const int C = 1e4 + 7;
const int D = 5e5 + 7;
const int E = 1e6 + 7;
const int F = 1e7 + 7;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
ll Gcd(ll num1, ll num2) {return !num2 ? num1 : Gcd(num2, num1 % num2);}
ll tx, ty, tz; void Exgcd(ll num1, ll num2) {if(num2 == 0) {tx = 1, ty = 0; return;}
	Exgcd(num2, num1 % num2), tz = tx, tx = ty, ty = tz - num1 / num2 * ty;}
/*General solution: tx += num2 / gcd * k, ty += num1 / gcd * k, k belong to Z*/
ll Gmul(ll x, ll y) {ll ans = 0; while(y != 0) {if(y & 1) ans = (ans + x) % mod; x = (x + x) % mod, y >>= 1;} return ans;}
ll Gpow(ll base, ll pow) {ll ans = 1;while(pow) {if(pow & 1) ans = Gmul(ans, base); base = Gmul(base, base);pow >>= 1;} return ans;}
ll Qpow(ll base, ll pow) {ll ans = 1;while(pow) {if(pow & 1) ans = (ans * base) % mod; base = (base * base) % mod;pow >>= 1;} return ans;}
inline int read() {register int x = 0, t = 1; register char ch = getchar();
while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar(); if(ch == '-') {t = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = x * 10 + ch - 48; ch = getchar();}return x * t;}
bool cmpbts(ll a, ll b) {return a > b;}
bool cmpstb(ll a, ll b) {return a < b;}
/*----------------------------------------*/
char s[D];
int dp[D][4], f[D][4], cnt;
int ans1 = 1;
void dfs(int x) {
	if(s[x] == '0') {
		f[x][0] = dp[x][0] = 1;
		return;
	}
	dfs(++ cnt);
	if(s[x] == '1') {
		dp[x][0] = max(dp[x + 1][1], dp[x + 1][2]) + 1;
		dp[x][1] = max(dp[x + 1][0], dp[x + 1][2]);
		dp[x][2] = max(dp[x + 1][0], dp[x + 1][1]);
		f[x][0] = min(f[x + 1][1], f[x + 1][2]) + 1;
		f[x][1] = min(f[x + 1][0], f[x + 1][2]);
		f[x][2] = min(f[x + 1][0], f[x + 1][1]);
	}
	else {
		int k = ++ cnt;
		dfs(k);
		dp[x][0] = max(dp[x + 1][1] + dp[k][2], dp[x + 1][2] + dp[k][1]) + 1;
		dp[x][1] = max(dp[x + 1][0] + dp[k][2], dp[x + 1][2] + dp[k][0]);
		dp[x][2] = max(dp[x + 1][0] + dp[k][1], dp[x + 1][1] + dp[k][0]);
		f[x][0] = min(f[x + 1][1] + f[k][2], f[x + 1][2] + f[k][1]) + 1;
		f[x][1] = min(f[x + 1][0] + f[k][2], f[x + 1][2] + f[k][0]);
		f[x][2] = min(f[x + 1][0] + f[k][1], f[x + 1][1] + f[k][0]);
	}
	ans1 = max(ans1, dp[x][0]);
}
int main() {
	scanf("%s", s + 1);
	dfs(++ cnt);
	cout << ans1 << " " << min(f[1][0], min(f[1][1], f[1][2])) << "\n";
	return 0;
}
posted @ 2022-06-04 22:32  zcxxxxx  阅读(21)  评论(0编辑  收藏  举报