Codeforces VK Cup 2015 - Round 2 (unofficial online mirror, Div. 1 only)
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 }
C题:
数学题。
P先走,V后走。首先计算P的最小步数:xp+yp,V的最小步数:max(xv,yv)。
显然,如果P的最小步数小于V的最小步数,那么P赢(因为V是挡不住P的)
否则,我们需要考虑两种情况:
(1)P能挡住V
我们发现只要P能在某个时刻挡住V的对角线方向,接着P就跟着V平行移动,那么P就赢。
那么只要P能比V先到达其对角线上某点就是P赢。可以用(xp <= xv && yp <= yv)判断
(2)P挡不住V,此时P的最小步数较大,V赢
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <vector> 5 #include <map> 6 #include <set> 7 #include <stack> 8 #include <queue> 9 #include <string> 10 #include <iostream> 11 #include <algorithm> 12 using namespace std; 13 14 #define MEM(a,b) memset(a,b,sizeof(a)) 15 #define REP(i,n) for(int i=0;i<(n);++i) 16 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 17 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 18 #define MP(a,b) make_pair(a,b) 19 20 typedef long long ll; 21 typedef pair<int,int> pii; 22 const int INF = (1 << 30) - 1; 23 24 int x1,y1,x2,y2; 25 26 int main(){ 27 scanf("%d%d%d%d",&x1,&y1,&x2,&y2); 28 int A = x1 + y1; 29 int B = max(x2,y2); 30 if(A <= B || (x1 <= x2 && y1 <= y2)) printf("Polycarp\n"); 31 else printf("Vasiliy\n"); 32 return 0; 33 }
E题:
一开始就做的这题... 第一次打的分类讨论... 后来精简了一下思路就过了。
找到第一个不匹配点 st 和最后一个不匹配点 ed,那么我们只要考虑两段串的 s[st ~ ed] 部分。
因为这两段的头尾均不匹配,所以肯定要在头 / 尾上加一个字符构成大串。
那么只要把 s1[st~ed] 向左移一位,看 s1[st+1 ~ ed] 与 s2[st ~ ed -1] 是否匹配,
把 s1[st~ed] 向右移一位,看 s1[st ~ ed - 1] 与 s2[st+1 ~ ed] 是否匹配。
答案就是匹配的次数。不需要考虑其他情况。
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 = 100010; 25 26 int n; 27 char s1[MAXN],s2[MAXN]; 28 int vis[MAXN]; 29 30 int main(){ 31 scanf("%d",&n); 32 scanf("%s",s1 + 1); 33 scanf("%s",s2 + 1); 34 for(int i = 1; i <= n; ++i) if(s1[i] != s2[i]) vis[i] = 1; 35 int st = -1,ed; 36 for(int i = 1; i <= n; ++i) if(vis[i]){ 37 if(st == -1) st = i; 38 ed = i; 39 } 40 int ans = 0; 41 bool flag = true; 42 for(int i = st; i <= ed - 1; ++i) if(s1[i] != s2[i + 1]) flag = false; 43 if(flag) ans++; 44 flag = true; 45 for(int i = st + 1; i <= ed; ++i) if(s1[i] != s2[i - 1]) flag = false; 46 if(flag) ans++; 47 printf("%d\n",ans); 48 return 0; 49 }