AIM Tech Round 3 (Div. 2)
A
按题意模拟即可。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int main () { 5 int n, b, d; scanf("%d%d%d", &n, &b, &d); 6 int now = 0, cnt = 0; 7 for(int i = 1; i <= n; ++ i) { 8 int x; scanf("%d", &x); 9 if(x > b) continue; 10 now += x; 11 if(now > d) { 12 ++ cnt; 13 now = 0; 14 } 15 } 16 printf("%d\n", cnt); 17 return 0; 18 }
B
题意:在一个坐标轴上有n个点坐标为x1到xn,给一个a坐标,从这个点出发至少遍历n个点中的n - 1个,问最短距离是多少。
思路:贪心的思想,先往左后往右或者先往右后往左,注意特判一些特殊情况。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int x[100005]; 5 int main () { 6 int n, a; scanf("%d%d", &n, &a); 7 for(int i = 1; i <= n; ++ i) scanf("%d", x + i); 8 sort(x + 1, x + 1 + n); 9 if(n == 1) return 0 * puts("0"); 10 if(n == 2) return 0 * printf("%d\n", min(abs(a - x[1]), abs(a - x[2]))); 11 if(a <= x[1]) return 0 * printf("%d\n", abs(a - x[n - 1])); 12 if(a >= x[n]) return 0 * printf("%d\n", abs(a - x[2])); 13 int ans1 = min(2 * abs(a - x[1]) + abs(a - x[n - 1]), abs(a - x[1]) + 2 * abs(a - x[n - 1])); 14 int ans2 = min(2 * abs(a - x[2]) + abs(a - x[n]), abs(a - x[2]) + 2 * abs(a - x[n])); 15 int ans = min(ans1, ans2); 16 if(a >= x[n - 1]) ans = min(ans, abs(a - x[1])); 17 if(a <= x[2]) ans = min(ans, abs(a - x[n])); 18 printf("%d\n", ans); 19 return 0; 20 }
C
题意:给一个字符串,要求选其中的一个连续子串,子串上的字符按照题目的规则转变,求执行转变之后字典序最小的字符串。
思路:贪心,选最左边的能转变成更小的字符串的字符作为子串的开始位置,往后直到遇到字符a停止。要注意的是题目要求严格执行一次操作,所以字符串一开始就都是a的情况,要把最后一个a变成z。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 char s[100005]; 5 int main () { 6 scanf("%s", s); 7 int len = strlen(s); 8 bool use = false; 9 for(int i = 0; i < len; ++ i) { 10 if(use && s[i] == 'a') break; 11 else if(s[i] != 'a') { 12 use = true; 13 s[i] --; 14 } 15 } 16 if(!use) s[len - 1] = 'z'; 17 puts(s); 18 return 0; 19 }
D
题意:构造一个01串,其两个字符的子串00, 01, 10, 11的数量分别为a00, a01, a10, a11,如果存在这个01串,输出, 否则输出Impossible。
思路:从a00和a11的值我们可以算出字符串中0和1的个数,然后即可构造。但当a00,a11中有为0的情况下,需要特殊考虑。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 long long get(long long x) { 5 long long l = 1, r = 1000000; 6 while(l < r) { 7 long long m = (l + r) >> 1; 8 if(m * (m - 1) < 2 * x) l = m + 1; 9 else r = m; 10 } 11 return l; 12 } 13 14 int main () { 15 long long a, b, c, d; scanf("%lld%lld%lld%lld", &a, &b, &c, &d); 16 if(!a && !d) { 17 if(!b && !c) puts("1"); 18 else if(!b) { 19 if(c == 1) puts("10"); 20 else puts("Impossible"); 21 } else if(!c) { 22 if(b == 1) puts("01"); 23 else puts("Impossible"); 24 } else puts("Impossible"); 25 } else if(!a) { 26 long long one = get(d); 27 if(one * (one - 1) / 2 != d) return 0 * puts("Impossible"); 28 if(!b && !c) { 29 for(int i = 1; i <= one; ++ i) printf("1"); puts(""); 30 } else { 31 if(b + c == one) { 32 for(int i = 1; i <= c; ++ i) printf("1"); 33 printf("0"); 34 for(int i = c + 1; i <= one; ++ i) printf("1"); 35 puts(""); 36 } else puts("Impossible"); 37 } 38 } else if(!d) { 39 long long zero = get(a); 40 if(zero * (zero - 1) / 2 != a) return 0 * puts("Impossible"); 41 if(!b && !c) { 42 for(int i = 1; i <= zero; ++ i) printf("0"); puts(""); 43 } else { 44 if(b + c == zero) { 45 for(int i = 1; i <= b; ++ i) printf("0"); 46 printf("1"); 47 for(int i = b + 1; i <= zero; ++ i) printf("0"); 48 puts(""); 49 } else puts("Impossible"); 50 } 51 } else { 52 long long one = get(d), zero = get(a); 53 if(one * (one - 1) / 2 != d || zero * (zero - 1) / 2 != a) return 0 * puts("Impossible"); 54 long long num = (one + zero) * (one + zero - 1) / 2 - a - d; 55 if(b + c != num) return 0 * puts("Impossible"); 56 else { 57 int now1 = 0, now2 = 0; 58 while(now1 < zero || now2 < one) { 59 if(b >= one - now2) { 60 printf("0"); 61 b -= one - now2; 62 now1 ++; 63 } else { 64 printf("1"); 65 now2 ++; 66 } 67 } puts(""); 68 } 69 } 70 return 0; 71 }
E
题意:给一颗n个节点的树,对于树的每一个节点,进行一次操作后,问它是否能成为质心(centroid),质心是指去掉这个点后,剩下的每个联通的子树的最大节点不超过n/2。
操作是先删除一条已有的边,然后再连一条新的边。
思路:考虑树形dp,dp1[u]表示以u为根节点时,它的子树最大可分裂出的节点数, 然后一遍dfs求以1为根的情况再一遍dfs求答案即可。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int idxE; 5 struct EDGE { 6 int v, next; 7 }edge[400005 << 1]; 8 int head[400005]; 9 10 void add_edge(int u, int v) { 11 ++ idxE; 12 edge[idxE].v = v; 13 edge[idxE].next = head[u]; 14 head[u] = idxE; 15 } 16 17 int n, ans[400005]; 18 int sz[400005], dp1[400005], dp2[400004]; 19 20 void dfs(int u, int fa) { 21 sz[u] = 1; 22 for(int i = head[u]; i; i = edge[i].next) if(edge[i].v != fa) { 23 int v = edge[i].v; 24 dfs(v, u); 25 sz[u] += sz[v]; 26 dp1[u] = max(dp1[u], dp1[v]); 27 } 28 if(sz[u] <= n / 2) dp1[u] = sz[u]; 29 } 30 31 void getans(int u, int fa) { 32 ans[u] = 1; 33 if(sz[u] <= n / 2) { 34 if(n - sz[u] - dp2[u] > n / 2) ans[u] = 0; 35 } else { 36 for(int i = head[u]; i; i = edge[i].next) if(edge[i].v != fa) { 37 int v = edge[i].v; 38 if(sz[v] - dp1[v] > n / 2) ans[u] = 0; 39 } 40 } 41 int ma = -1, mav; 42 for(int i = head[u]; i; i = edge[i].next) if(edge[i].v != fa) { 43 int v = edge[i].v; 44 if(dp1[v] > ma) ma = dp1[v], mav = v; 45 } 46 for(int i = head[u]; i; i = edge[i].next) if(edge[i].v != fa) { 47 int v = edge[i].v; 48 if(v == mav) { 49 dp2[v] = dp2[u]; 50 for(int j = head[u]; j; j = edge[j].next) if(edge[j].v != mav && edge[j].v != fa) { 51 int vv = edge[j].v; 52 dp2[v] = max(dp2[v], dp1[vv]); 53 } 54 } else dp2[v] = max(dp2[u], ma); 55 if(n - sz[v] <= n / 2) dp2[v] = n - sz[v]; 56 getans(v, u); 57 } 58 } 59 60 int main () { 61 scanf("%d", &n); 62 for(int i = 1; i <= n - 1; ++ i) { 63 int u, v; scanf("%d%d", &u, &v); 64 add_edge(u, v), add_edge(v, u); 65 } 66 dfs(1, -1); 67 getans(1, -1); 68 for(int i = 1; i <= n; ++ i) printf("%d ", ans[i]); 69 return 0; 70 }