比赛-6月Round1
Posted ghcred
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了比赛-6月Round1相关的知识,希望对你有一定的参考价值。
A.饥饿的奶牛
想到线段覆盖问题的贪心解法,比如根据线段长度排序再选(据加藤惠实测能过 20% 数据),比如根据左端点为第一关键字,右端点为第二关键字排序再选……胡乱画图发现都不行。然后考虑 DP,f[i][j] 表示前 i 条线段选 j 条的最大收益,期望从 f[i-1][j-1] 和 f[i][j-1] 转移,发现不满足 DP 性质,因为子问题解不包含于当前问题解集中(最佳方式选 i-1 条后不一定能构造出选 i 条的最佳方案)。然后我想了下搜索……选一条线段之后,它包含的区间所在的线段不能再选,限制好像比较强,但是时间复杂度玄学……
正解: 对线段 [x, y] ,从 x 向 y+1 连一条权值为 y-x+1 的边。对每个点 i 向 i+1 连权值为 0 的边。设置一个源点,向所有点连权值为 0 的边。从源点开始进行最长路算法,答案是 max{ dis[i] }。
类似“何老板看守果园”,不过考试的时候并没有想到那道题。真的没想到 A 题这么难,太坑了OrzOrzOrz。
B.平衡的队列
正解: 以 x 坐标为关键字从小到大排序。讨论每个点,把种族 0 作为种族 -1 处理,这样可以让 1 和 -1 在累加中互相“消除”。设前缀和 sum[i] ,若 sum[x-1] = sum[y],则 [x, y] 是一段“平衡”的区间。对于所有 sum 值相同的位置,显然希望得到最右的位置 R[v] 和最左的位置 L[v],用 X 表示一点的 x 坐标,那么这样一组 L R 对答案的贡献是 X[R[v]] - X[L[v]+1] ,在所有合理的方案里取最大值就是最终答案。
C.颜色间距
正解: 对每个颜色,记录任意一个深度最深的节点 x ,max{ length(x, i) } 就是这个颜色的答案,其中 i 是这个颜色中不是 x 的其它点。求 length(a, b) ,可以找到 LCA(a, b) = c ,那么路径长度为 depth(a) + depth(b) - 2 * depth(c)
如果一个节点的子树中有和它相同颜色的节点,那么显然比起这个节点,它的子节点更适合作为一条路径的一端。所以期望一个节点没有相同颜色的节点在它的子树中,找到这个颜色深度最大的节点即可。
D.和谐数
正解: 用树状数组就非常好写。从左往右讨论每个值 A[i] ,L[i] 表示 i 左边更大的数的个数,L[i] = GetSum(INF)-GetSum(A[i]) 然后再 Modify(A[i], 1)。同理得到 R[i],然后算答案。注意离散化(排序)。
1 #include <stdio.h> 2 #include <algorithm> 3 #include <queue> 4 #include <vector> 5 6 using namespace std; 7 8 const int INF = 1e9; 9 const int _N = 2100; 10 11 struct edge { 12 int v, w; 13 edge(int v = 0, int w = 0): 14 v(v), w(w) { } 15 }; 16 17 vector<edge> G[_N]; 18 queue<int> Q; 19 int dis[_N]; 20 bool mk[_N]; 21 22 void Ins(int t1, int t2, int t3) { G[t1].push_back(edge(t2, t3)); return; } 23 24 void SPFA(int beg) 25 { 26 int i; 27 for (i = 0; i <= 2011; ++i) 28 dis[i] = -INF, mk[i] = false; 29 while (!Q.empty()) Q.pop(); 30 dis[beg] = 0, Q.push(beg), mk[beg] = true; 31 while (!Q.empty()) { 32 int p = Q.front(); 33 Q.pop(); mk[p] = false; 34 for (i = G[p].size()-1; i >= 0; --i) { 35 edge v = G[p][i]; 36 if (dis[v.v] < dis[p] + v.w) { 37 dis[v.v] = dis[p] + v.w; 38 if (!mk[v.v]) Q.push(v.v), mk[v.v] = true; 39 } 40 } 41 } 42 return; 43 } 44 45 int main() 46 { 47 int N, i; 48 scanf("%d", &N); 49 for (i = 1; i <= N; ++i) { 50 int t1, t2; 51 scanf("%d%d", &t1, &t2); 52 if (t1 > t2) swap(t1, t2); 53 Ins(t1, t2+1, t2+1-t1); 54 } 55 for (i = 1; i <= 2010; ++i) Ins(i, i+1, 0), Ins(0, i, 0); 56 SPFA(0); 57 int ans = 0; 58 for (i = 1; i <= 2011; ++i) ans = max(ans, dis[i]); 59 printf("%d ", ans); 60 return 0; 61 }
1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 5 using namespace std; 6 7 const int _N = 51000; 8 const int INF = 1e9; 9 10 struct data { 11 int val, x; 12 bool operator < (const data &tmp) const 13 { 14 return x < tmp.x; 15 } 16 } A[_N]; 17 18 int L[_N*2], R[_N*2]; 19 20 int main() 21 { 22 int i, sum, mx_sum, mn_sum, ans, N; 23 scanf("%d", &N); 24 for (i = 1; i <= N; ++i) { 25 scanf("%d%d", &A[i].val, &A[i].x); 26 if (!A[i].val) A[i].val = -1; 27 } 28 sort(A+1, A+1+N); 29 30 memset(L, -1, sizeof L), memset(R, -1, sizeof R); 31 sum = mx_sum = mn_sum = 0; 32 L[sum+_N] = R[sum+_N] = 0; 33 34 for (i = 1; i <= N; ++i) { 35 mx_sum = max(mx_sum, sum += A[i].val); 36 mn_sum = min(mn_sum, sum); 37 if (L[sum+_N] == -1) L[sum+_N] = i; 38 R[sum+_N] = i; 39 } 40 ans = 0; 41 for (i = mn_sum; i <= mx_sum; ++i) 42 if (L[i+_N] != -1 && L[i+_N] < R[i+_N]) 43 ans = max(ans, A[R[i+_N]].x-A[L[i+_N]+1].x); 44 printf("%d ", ans); 45 return 0; 46 }
1 #include <stdio.h> 2 #include <algorithm> 3 #include <vector> 4 #include <math.h> 5 6 using namespace std; 7 8 const int _N = 200105; 9 10 vector<int> G[_N], P[_N]; 11 int mxd, lg_mxd; 12 int depth[_N], X[_N], Clr[_N], dad[_N][20]; 13 14 void DFS(int node, int d) 15 { 16 mxd = max(mxd, depth[node] = d); 17 if (!X[Clr[node]] || depth[X[Clr[node]]] < depth[node]) 18 X[Clr[node]] = node; 19 for (int i = G[node].size()-1; i >= 0; --i) 20 DFS(G[node][i], d+1); 21 return; 22 } 23 24 int LCA(int x, int y) 25 { 26 if (depth[x] < depth[y]) swap(x, y); 27 int t = depth[x]-depth[y], i; 28 for (i = lg_mxd; i >= 0; --i) 29 if ((t>>i) & 1) x = dad[x][i]; 30 if (x == y) return x; 31 for (i = lg_mxd; i >= 0; --i) 32 if (dad[x][i] != dad[y][i]) 33 x = dad[x][i], y = dad[y][i]; 34 return dad[x][0]; 35 } 36 37 int main() 38 { 39 int N, M, i, c, j, root; 40 scanf("%d%d", &N, &M); 41 for (i = 1; i <= N; ++i) { 42 scanf("%d%d", &Clr[i], &dad[i][0]); 43 P[Clr[i]].push_back(i); 44 if (!dad[i][0]) root = i; 45 else G[dad[i][0]].push_back(i); 46 } 47 DFS(root, 1); 48 lg_mxd = log2(mxd+0.5)+1; 49 for (j = 1; j <= lg_mxd; ++j) 50 for (i = 1; i <= N; ++i) 51 dad[i][j] = dad[dad[i][j-1]][j-1]; 52 for (c = 1; c <= M; ++c) { 53 int ans = -1; 54 for (i = P[c].size()-1; i >= 0; --i) 55 if (P[c][i] != X[c]) 56 ans = max(ans, depth[X[c]]+depth[P[c][i]]-2-(depth[LCA(X[c], P[c][i])]-1)*2); 57 printf("%d ", ans); 58 } 59 return 0; 60 }
1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 5 using namespace std; 6 7 const int _N = 101005; 8 9 struct data { 10 int val, id; 11 } A[_N]; 12 13 int cnt; 14 int B[_N], C[_N], L[_N], R[_N]; 15 16 bool val_first(data t1, data t2) { return t1.val < t2.val; } 17 18 inline int lbt(int v) { return v & (-v); } 19 20 int GetSum(int k) 21 { 22 int tmp = 0; 23 for (int i = k; i; i ^= lbt(i)) tmp += C[i]; 24 return tmp; 25 } 26 27 void Modify(int k, int d) 28 { 29 for (int i = k; i <= cnt; i += lbt(i)) C[i] += d; 30 return; 31 } 32 33 int main() 34 { 35 int N, i; 36 scanf("%d", &N); 37 for (i = 1; i <= N; ++i) 38 scanf("%d", &A[i].val), A[i].id = i; 39 sort(A+1, A+1+N, val_first); 40 41 B[A[1].id] = cnt = 1; 42 for (i = 2; i <= N; ++i) 43 B[A[i].id] = A[i].val == A[i-1].val ? B[A[i-1].id] : (++cnt); 44 for (i = 1; i <= N; ++i) 45 L[i] = GetSum(cnt)-GetSum(B[i]), Modify(B[i], 1); 46 memset(C, 0, sizeof C); 47 for (i = N; i >= 1; --i) 48 R[i] = GetSum(cnt)-GetSum(B[i]), Modify(B[i], 1); 49 int ans = 0; 50 for (i = 1; i <= N; ++i) 51 if (max(L[i], R[i]) > 2*min(L[i], R[i])) ++ans; 52 printf("%d ", ans); 53 return 0; 54 }
以上是关于比赛-6月Round1的主要内容,如果未能解决你的问题,请参考以下文章
2022年,ICPC比赛CCPC比赛CCF-CSP考试蓝桥杯比赛天梯赛日程
两个乒乓球队进行比赛,各出三人。甲队为a,b,c三人,乙队为x,y,z三人。 已抽签决定比赛名单。有人向队员打听比赛的名单。 a说他不和x比,c说他不和x,z比,请编程序找出三队赛手的名单。(代码片段