2015-04-18 14:47:35

总结:难度没有顺序的一场... 打得我毫无脾气... 认清了自己的实力。

  接下来要调整了下状态了... 静下心,提高效率,老老实实地去攻克专题和训练赛。

  比赛仅做了两题,E和C... 然后一直在做B题,wa7,最后虽然知道如何错,但已经来不及改了。

  

B题

  比赛时死活都用一维的dp来搞... 后来发现自己too young,半夜时脑子转不过来,也不愿意换算法了...

  正解是树形DP,用dp[i][1 / 0]来记录以 i 号节点为根的子树中取奇数 / 偶数个点能构成的最大合法解。

  由于点有序,我们从最后一个点 n 开始倒序考虑:

    对于第 i 号节点,我们要根据其子节点的dp[son][1 / 0]来计算dp[i][1 / 0]

    实际上我们要在这一层再来一个DP,DP[i][0 / 1]表示考虑前 i 个儿子取奇数 / 偶数个节点能构成的最大值。

    那么就有 dp[i][0] = DP[num of son][0]

        dp[i][1] = max(DP[num of son][1] , dp[i][0] + a[i]](算dp[i][1]还要考虑加上dp[i][0]加上根节点本身)

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cmath>
 5 #include <vector>
 6 #include <map>
 7 #include <set>
 8 #include <stack>
 9 #include <queue>
10 #include <string>
11 #include <iostream>
12 #include <algorithm>
13 using namespace std;
14 
15 #define MEM(a,b) memset(a,b,sizeof(a))
16 #define REP(i,n) for(int i=0;i<(n);++i)
17 #define FOR(i,a,b) for(int i=(a);i<=(b);++i)
18 #define getmid(l,r) ((l) + ((r) - (l)) / 2)
19 #define MP(a,b) make_pair(a,b)
20 
21 typedef long long ll;
22 typedef pair<int,int> pii;
23 const int INF = (1 << 30) - 1;
24 const int MAXN = 200010;
25 
26 int n;
27 int A[MAXN];
28 ll dp[MAXN][2],DP[MAXN][2];
29 vector<int> g[MAXN];
30 
31 int main(){
32     int a;
33     scanf("%d",&n);
34     FOR(i,1,n){
35         scanf("%d%d",&a,&A[i]);
36         if(a != -1) g[a].push_back(i);
37     }
38     for(int i = n; i >= 1; --i){
39         int sz = g[i].size();
40         DP[0][0] = 0;
41         DP[0][1] = -INF;
42         for(int j = 0; j < sz; ++j){
43             int v = g[i][j];
44             DP[j + 1][0] = max(DP[j][0] + dp[v][0],DP[j][1] + dp[v][1]);
45             DP[j + 1][1] = max(DP[j][0] + dp[v][1],DP[j][1] + dp[v][0]);
46         }
47         dp[i][0] = DP[sz][0];
48         dp[i][1] = max(DP[sz][1],dp[i][0] + A[i]);
49     }
50     cout << max(dp[1][0],dp[1][1]) << endl;
51     return 0;
52 }
View Code

相关文章: