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 }