“访问”美术馆
这是一道神奇的树形DP,对它还是不需要建树,而且完全可以一边读入,一边DP出结果……
首先我们看题目描述很显然是一棵二叉树,而且还是完全二叉树。(没啥卵用)
令dp[i][j]表示在第i个节点选取花费j时间所能获取的最大画数。
之后因为题目的输入是递归给出的……所以我们直接去建图难度很大,不妨直接边递归边求解。首先我们考虑,如果当前的节点是一个不会再分裂的点(他下面直接通向展览馆)。我们直接更新这个节点的答案就可以。
之后如果他要能再分裂,先递归下去,之后在返回的途中,枚举对于左子树给其分配的偷窃时间,这样进行合并就可以啦。
注意因为这哥们偷完东西得跑出去,所以相当于每条道路的权值要<<1,还有就是他必须在警察来之前1秒必须跑出去,所以读入要--。
然后就可以做了。
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<queue> #include<set> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define enter putchar('\n') using namespace std; typedef long long ll; const int M = 100005; int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { ans *= 10; ans += ch - '0'; ch = getchar(); } return ans * op; } int cnt,tot,n,m,dp[105][605]; void dfs() { int ro = ++cnt,lim; lim = read(),tot = read(),lim <<= 1; if(tot) rep(t,lim,n) dp[ro][t] = min((t-lim) / 5,tot);//已经到展览馆就更新 else { int l = cnt+1;dfs(); int r = cnt+1;dfs(); rep(t,lim,n) rep(lt,0,t-lim) dp[ro][t] = max(dp[ro][t],dp[l][lt] + dp[r][t-lt-lim]);//更新答案 } } int main() { n = read(),n--; dfs(); printf("%d\n",dp[1][n]); return 0; }
当你意识到,每个上一秒都成为永恒。