P2585 [ZJOI2006]三色二叉树-Solution
Link
经典区间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;
}