agc034
A:题意:你有一个1 * n的网格,有些地方是障碍。你有两个人,分别要从a到b和从c到d,一次只能向右跳1步或者两步。求是否可行。
解:先判断有没有2个连续的障碍,然后判断是否能错车。
1 #include <bits/stdc++.h> 2 3 const int N = 200010; 4 5 char str[N]; 6 7 int main() { 8 int n, a, b, c, d; 9 scanf("%d%d%d%d%d", &n, &a, &b, &c, &d); 10 scanf("%s", str + 1); 11 if(c < d) { 12 for(int i = a; i < d; i++) { 13 if(str[i] == '#' && str[i + 1] == '#') { 14 printf("No\n"); 15 return 0; 16 } 17 } 18 printf("Yes\n"); 19 return 0; 20 } 21 else { 22 for(int i = a; i < c; i++) { 23 if(str[i] == '#' && str[i + 1] == '#') { 24 printf("No\n"); 25 return 0; 26 } 27 } 28 for(int i = b; i <= d; i++) { 29 if(str[i - 1] == '.' && str[i] == '.' && str[i + 1] == '.') { 30 printf("Yes\n"); 31 return 0; 32 } 33 } 34 printf("No\n"); 35 return 0; 36 } 37 return 0; 38 }
B:题意:你有一个ABC字符串,你能进行的操作就是把某个ABC变成BCA。求最多进行多少次操作。
解:发现可以把BC看做一个整体。单独的B和C看做障碍物。
那么对于每一段无障碍物的连续A,BC,求逆序对就好了。
1 #include <bits/stdc++.h> 2 3 typedef long long LL; 4 const int N = 200010; 5 6 char str[N]; 7 bool vis[N]; 8 9 int main() { 10 11 scanf("%s", str + 1); 12 int n = strlen(str + 1); 13 for(int i = 1; i <= n; i++) { 14 if(str[i] == 'C' && str[i - 1] != 'B') { 15 vis[i] = 1; 16 } 17 if(str[i] == 'B' && str[i + 1] != 'C') { 18 vis[i] = 1; 19 } 20 } 21 LL ans = 0; 22 for(int l = 1, r; l <= n; l = r + 1) { 23 while(vis[l]) { 24 ++l; 25 } 26 if(l > n) break; 27 r = l; 28 while(!vis[r + 1] && r < n) { 29 ++r; 30 } 31 LL cnt = 0, t = 0; 32 for(int i = l; i <= r; i++) { 33 if(str[i] == 'A') { 34 ++cnt; 35 } 36 else if(str[i] == 'B' && str[i + 1] == 'C') { 37 ++i; 38 t += cnt; 39 } 40 } 41 ans += t; 42 } 43 printf("%lld\n", ans); 44 return 0; 45 }
C:题意:你有n场考试,满分X分。你的对手每场考试得了bi分。你每学习一个小时就能把某场考试提高1分。你能给每场考试选择一个li~ri之间的加权。求你最少花多少小时才能不比对手考的低。
解:发现加权要么是li要么是ri。且你比对手高就是ri,否则就是li。
然后发现如果有两场考试都没有满分,最优策略是把一场考试的分挪到另一场上。
然后就发现答案一定是若干场满分和一场非满分。这时候就可以排序了,然后二分答案,枚举非满分是哪一场。
1 #include <bits/stdc++.h> 2 3 typedef long long LL; 4 const int N = 100010; 5 6 struct Node { 7 LL l, r, b, h; 8 inline bool operator < (const Node &w) const { 9 return h > w.h; 10 } 11 }node[N]; 12 13 LL X, D, sum[N]; 14 int n; 15 16 inline LL cal(LL a, LL i) { 17 if(a <= node[i].b) { 18 return a * node[i].l; 19 } 20 return node[i].b * node[i].l + (a - node[i].b) * node[i].r; 21 } 22 23 inline bool check(LL k) { 24 LL ans = 0, r = k % X, t = k / X; 25 if(t >= n) { 26 return sum[n]; 27 } 28 // printf("r = %lld t = %lld \n", r, t); 29 for(int i = 1; i <= n; i++) { 30 if(i <= t) ans = std::max(ans, cal(r, i) + sum[t + 1] - node[i].h); 31 else { 32 ans = std::max(ans, cal(r, i) + sum[t]); 33 } 34 } 35 //printf("k = %lld ans = %lld D = %lld \n", k, ans, D); 36 return ans >= D; 37 } 38 39 int main() { 40 41 scanf("%d%lld", &n, &X); 42 for(int i = 1; i <= n; i++) { 43 scanf("%lld%lld%lld", &node[i].b, &node[i].l, &node[i].r); 44 node[i].h = node[i].b * node[i].l + (X - node[i].b) * node[i].r; 45 D += node[i].b * node[i].l; 46 } 47 std::sort(node + 1, node + n + 1); 48 for(int i = 1; i <= n; i++) { 49 sum[i] = sum[i - 1] + node[i].h; 50 } 51 LL l = 0, r = 4e18; 52 while(l < r) { 53 LL mid = (l + r) >> 1; 54 if(check(mid)) { 55 r = mid; 56 } 57 else { 58 l = mid + 1; 59 } 60 } 61 printf("%lld\n", r); 62 return 0; 63 }
D:题意:给你平面上两组n个点,你要把它们配对,使得曼哈顿距离最大。n <= 1000。
解:曼哈顿距离有2个绝对值,拆开就是4种情况。直接建4个中转点表示这4种情况,跑最大费用最大流。
1 #include <bits/stdc++.h> 2 3 #define int LL 4 5 typedef long long LL; 6 const int N = 2010, INF = 0x3f3f3f3f3f3f3f3fll; 7 8 struct Edge { 9 int nex, v, c, len; 10 Edge(){} 11 Edge(int N, int V, int C, int L) { 12 nex = N, v = V, c = C, len = L; 13 } 14 }edge[2000010]; int tp = 1; 15 16 int e[N], n, tot, d[N], pre[N], flow[N], Time, vis[N]; 17 std::queue<int> Q; 18 19 inline void add(int x, int y, int z, int w) { 20 edge[++tp] = Edge(e[x], y, z, w); 21 e[x] = tp; 22 edge[++tp] = Edge(e[y], x, 0, -w); 23 e[y] = tp; 24 return; 25 } 26 27 inline bool SPFA(int s, int t) { 28 memset(d, 0x3f, sizeof(d)); 29 Q.push(s); 30 ++Time; 31 d[s] = 0; 32 vis[s] = Time; 33 flow[s] = INF; 34 while(Q.size()) { 35 int x = Q.front(); 36 Q.pop(); 37 vis[x] = 0; 38 for(int i = e[x]; i; i = edge[i].nex) { 39 int y = edge[i].v; 40 if(edge[i].c && d[y] > d[x] + edge[i].len) { 41 d[y] = d[x] + edge[i].len; 42 pre[y] = i; 43 flow[y] = std::min(flow[x], edge[i].c); 44 if(vis[y] != Time) { 45 vis[y] = Time; 46 Q.push(y); 47 } 48 } 49 } 50 } 51 return d[t] < INF; 52 } 53 54 inline void update(int s, int t) { 55 int f = flow[t]; 56 while(s != t) { 57 int i = pre[t]; 58 edge[i].c -= f; 59 edge[i ^ 1].c += f; 60 t = edge[i ^ 1].v; 61 } 62 return; 63 } 64 65 inline int solve(int s, int t, int &cost) { 66 cost = 0; 67 int ans = 0; 68 while(SPFA(s, t)) { 69 //printf("!"); 70 ans += flow[t]; 71 cost += flow[t] * d[t]; 72 update(s, t); 73 } 74 return ans; 75 } 76 77 signed main() { 78 79 scanf("%lld", &n); 80 int s = 2 * n + 5, t = s + 1, x, y, z; 81 for(int i = 1; i <= n; i++) { 82 scanf("%lld%lld%lld", &x, &y, &z); 83 add(s, i, z, 0); 84 add(i, 2 * n + 1, z, x + y); 85 add(i, 2 * n + 2, z, y - x); 86 add(i, 2 * n + 3, z, x - y); 87 add(i, 2 * n + 4, z, -x - y); 88 } 89 for(int i = 1; i <= n; i++) { 90 scanf("%lld%lld%lld", &x, &y, &z); 91 add(n + i, t, z, 0); 92 add(2 * n + 1, n + i, z, -x - y); 93 add(2 * n + 2, n + i, z, x - y); 94 add(2 * n + 3, n + i, z, y - x); 95 add(2 * n + 4, n + i, z, x + y); 96 } 97 //puts("OVER"); 98 int cost = 0; 99 solve(s, t, cost); 100 printf("%lld\n", -cost); 101 return 0; 102 }