2017-2018 ACM-ICPC Latin American Regional Programming Contest Solution
Posted dup4
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2017-2018 ACM-ICPC Latin American Regional Programming Contest Solution相关的知识,希望对你有一定的参考价值。
A - Arranging tiles
留坑。
B - Buggy ICPC
题意:给出一个字符串,然后有两条规则,如果打出一个辅音字母,直接接在原字符串后面,如果打出一个元音字母,那么接在原来的字符串后面之后再翻转整个字符串,在这两条规则之下,求有多少种打印给定字符串的方法
思路:如果第一个字符是辅音,那么答案为0
如果全是辅音或全是元音,那么答案为1
如果只有一个辅音,答案为len
否则是最中间两个元音中间的辅音字符个数+1
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define N 100010 6 7 char s[N]; 8 9 bool vis[210]; 10 11 inline void Init() 12 { 13 vis[‘a‘] = 1; 14 vis[‘e‘] = 1; 15 vis[‘i‘] = 1; 16 vis[‘o‘] = 1; 17 vis[‘u‘] = 1; 18 } 19 20 inline int work() 21 { 22 int len = strlen(s); 23 if (len == 1) return 1; 24 int cnt = 0; 25 for (int i = 0; i < len; ++i) if (vis[s[i]]) cnt++; 26 if (cnt == 0 || cnt == len) return 1; 27 if (!vis[s[0]]) return 0; 28 if (cnt == 1) return len; 29 int l = 0, r = len - 1; 30 while (vis[s[r]] == 0) --r; 31 int flag = 0; 32 for (; true; flag ^= 1) 33 { 34 cnt = 0; 35 if (flag == 0) 36 { 37 ++l; 38 while (true) 39 { 40 if (l == r) return cnt + 1; 41 if (vis[s[l]]) break; 42 ++cnt;++l; 43 } 44 } 45 else 46 { 47 --r; 48 while (true) 49 { 50 if (l == r) return cnt + 1; 51 if (vis[s[r]]) break; 52 ++cnt;--r; 53 } 54 } 55 } 56 } 57 58 int main() 59 { 60 Init(); 61 while (scanf("%s", s) != EOF) 62 { 63 printf("%d ", work()); 64 } 65 return 0; 66 }
C - Complete Naebbirac‘s sequence
题意:可以有三种操作, 一种是可以加上一个数,一种是可以减去一个数,一种是可以改变一个数 使得所有数出现次数相同,只能有一个操作,如果不能完成,输出"*"
思路:
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 1e3 + 10; 6 const int INF = 0x3f3f3f3f; 7 8 int k, n; 9 int arr[maxn]; 10 int Max, Min, Mx, Mn; 11 12 inline bool check() 13 { 14 for(int i = 2; i <= k; ++i) 15 { 16 if(arr[i] != arr[1]) return false; 17 } 18 return true; 19 } 20 21 int main() 22 { 23 while(~scanf("%d %d", &k, &n)) 24 { 25 memset(arr, 0, sizeof arr); 26 for(int i = 0 , num; i < n; ++i) 27 { 28 scanf("%d", &num); 29 arr[num]++; 30 } 31 Max = -INF, Min = INF; 32 for(int i = 1; i <= k; ++i) 33 { 34 if(arr[i] > Max) 35 { 36 Max = arr[i]; 37 Mx = i; 38 } 39 if(arr[i] < Min) 40 { 41 Min = arr[i]; 42 Mn = i; 43 } 44 } 45 if((n - 1) % k == 0) 46 { 47 --arr[Mx]; 48 if(check()) 49 { 50 printf("-%d ", Mx); 51 continue; 52 } 53 ++arr[Mx]; 54 } 55 if((n + 1) % k == 0) 56 { 57 ++arr[Mn]; 58 if(check()) 59 { 60 printf("+%d ", Mn); 61 continue; 62 } 63 --arr[Mn]; 64 } 65 ++arr[Mn]; 66 --arr[Mx]; 67 if(check()) 68 { 69 printf("-%d +%d ", Mx, Mn); 70 continue; 71 } 72 printf("* "); 73 74 } 75 return 0; 76 }
D - Daunting device
留坑。
E - Enigma
题意:给出两个数,有一个数中某些位是空的,填充空的位,使得左边那个数能够整除右边的数,并且左边那个数最小
思路:
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 1e3 + 10; 6 7 bool flag[maxn][maxn]; 8 int vis[maxn][maxn]; 9 string str; 10 string ans; 11 int len; 12 int m; 13 14 inline bool DFS(int idx, int res) 15 { 16 if(idx >= len) 17 { 18 return res == 0; 19 } 20 if(vis[idx][res] != -1) return flag[idx][res]; 21 vis[idx][res] = 1; 22 bool &ret = flag[idx][res]; 23 if(str[idx] == ‘?‘) 24 { 25 for(int i = !idx; i <= 9; ++i) 26 { 27 ret |= DFS(idx + 1, (res * 10 + i) % m); 28 if(ret) return true; 29 } 30 return false; 31 } 32 else 33 { 34 ret |= DFS(idx + 1, (res * 10 + (str[idx] - ‘0‘)) % m); 35 } 36 return ret; 37 } 38 39 inline void WORK(int idx,int res) 40 { 41 if(idx == len) return ; 42 if(str[idx] == ‘?‘) 43 { 44 for(int i = !idx; i <= 9; ++i) 45 { 46 if(DFS(idx + 1, (res * 10 + i) % m)) 47 { 48 ans += (char)(i + ‘0‘); 49 WORK(idx + 1, (res * 10 + i) % m); 50 return ; 51 } 52 } 53 } 54 else 55 { 56 ans += str[idx]; 57 WORK(idx + 1, (res * 10 + str[idx] - ‘0‘) % m); 58 return ; 59 } 60 } 61 62 int main() 63 { 64 ios::sync_with_stdio(false); 65 cin.tie(0); 66 cout.tie(0); 67 while(cin >> str >> m) 68 { 69 memset(flag, 0, sizeof flag); 70 memset(vis, -1, sizeof vis); 71 len = str.length(); 72 if(DFS(0, 0)) 73 { 74 ans.clear(); 75 WORK(0, 0); 76 cout << ans << " "; 77 } 78 else 79 { 80 cout << "* "; 81 } 82 } 83 return 0; 84 }
F - Fundraising
题意:每个人有两个值,以及一个权值,若两个人都能选出来,那么要么两个人的值都相同,或者某个人的两个值分别大于另一个人,求选出一些人使得权值和最大
思路:两个值都相同的先合并,然后按一维排序,另一维做最大上升子序列权值和
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define N 100010 6 #define ll long long 7 typedef pair <int, int> pii; 8 9 struct node 10 { 11 int x, y; ll D; 12 inline node() {} 13 inline node(int x, int y, ll D) : x(x), y(y), D(D) {} 14 inline bool operator < (const node &r) const 15 { 16 return x < r.x || x == r.x && y > r.y; 17 } 18 }arr[N]; 19 20 map <pii, int> mp; 21 int n, m, cnt; 22 ll brr[N], a[N]; 23 24 inline int Get(pii x) 25 { 26 if (mp.find(x) == mp.end()) 27 { 28 mp[x] = ++cnt; 29 brr[cnt] = x.second; 30 arr[cnt] = node(x.first, x.second, 0); 31 } 32 return mp[x]; 33 } 34 35 inline void Init() 36 { 37 memset(a, 0, sizeof a); 38 sort(brr + 1, brr + 1 + cnt); 39 m = unique(brr + 1, brr + 1 + cnt) - brr - 1; 40 } 41 42 inline int lowbit(int x) 43 { 44 return x & (-x); 45 } 46 47 inline void update(int x, ll val) 48 { 49 for (int i = x; i <= m; i += lowbit(i)) 50 a[i] = max(a[i], val); 51 } 52 53 inline ll query(int x) 54 { 55 ll res = 0; 56 for (int i = x; i > 0; i -= lowbit(i)) 57 res = max(res, a[i]); 58 return res; 59 } 60 61 int main() 62 { 63 while (scanf("%d", &n) != EOF) 64 { 65 mp.clear(); cnt = 0; 66 int x, y; ll D; 67 for (int i = 1; i <= n; ++i) 68 { 69 scanf("%d%d%lld", &x, &y, &D); 70 int pos = Get(pii(x, y)); 71 arr[pos].D += D; 72 } 73 Init(); 74 for (int i = 1; i <= cnt; ++i) arr[i].y = lower_bound(brr + 1, brr + 1 + m, arr[i].y) - brr; 75 sort(arr + 1, arr + 1 + cnt); 76 for (int i = 1; i <= cnt; ++i) 77 { 78 ll v = query(arr[i].y - 1); 79 update(arr[i].y, v + arr[i].D); 80 } 81 printf("%lld ", query(m)); 82 } 83 return 0; 84 }
G - Gates of uncertainty
留坑。
H - Hard choice
水。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 int a[3], b[3]; 6 7 int main() 8 { 9 while (scanf("%d%d%d", &a[0], &a[1], &a[2]) != EOF) 10 { 11 for (int i = 0; i < 3; ++i) scanf("%d", b + i); 12 int ans = 0; 13 for (int i = 0; i < 3; ++i) ans += max(0, b[i] - a[i]); 14 printf("%d ", ans); 15 } 16 return 0; 17 }
I - Imperial roads
题意:给出一张图,然后询问给出一条边,求有这条边的最小生成树的权值和
思路:先求最小生成树,然后询问的边如果在最小生成树里面那么就是原来的权值和,否则在原来的最小生成树里面的加入一条边,形成个环,然后去掉这个环里面除了加入的边之外的边权最大的边
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 2e5 + 10; 6 const int DEG = 20; 7 8 typedef long long ll; 9 10 int n, m; 11 12 struct node{ 13 int u, v; 14 ll w; 15 inline node(){} 16 inline node(int u, int v, ll w) :u(u), v(v), w(w){} 17 inline bool operator < (const node &b)const 18 { 19 return w < b.w; 20 } 21 }; 22 23 struct Edge{ 24 int to; 25 int nxt; 26 ll w; 27 inline Edge(){} 28 inline Edge(int to, int nxt, ll w) :to(to), nxt(nxt), w(w){} 29 }edge[maxn << 1]; 30 31 int dis[maxn][DEG]; 32 bool inMST[maxn << 1]; 33 int head[maxn]; 34 int tot; 35 int father[maxn]; 36 vector<node>G; 37 int cnt; 38 map<pair<int,int>, int>mp; 39 40 inline void addedge(int u,int v, ll w) 41 { 42 edge[tot] = Edge(v, head[u], w); 43 head[u] = tot++; 44 } 45 46 inline void Init() 47 { 48 G.clear(); 49 cnt = 0; 50 tot = 0; 51 memset(dis, 0, sizeof dis); 52 memset(head, -1, sizeof head); 53 for(int i = 1; i <= n; ++i) 54 { 55 father[i] = i; 56 } 57 } 58 59 inline int find(int x) 60 { 61 return x == father[x] ? father[x] : father[x] = find(father[x]); 62 } 63 64 inline void mix(int x,int y) 65 { 66 x = find(x); 67 y = find(y); 68 if(x != y) 69 { 70 father[x] = y; 71 } 72 } 73 74 inline bool same(int x,int y) 75 { 76 return find(x) == find(y); 77 } 78 79 inline ll MST() 80 { 81 mp.clear(); 82 ll res = 0; 83 sort(G.begin(), G.end()); 84 memset(inMST, false, sizeof inMST); 85 for(auto it : G) 86 { 87 int u = it.u; 88 int v = it.v; 89 mp[make_pair(v, u)] = cnt; 90 mp[make_pair(u, v)] = cnt++; 91 } 92 for(auto it : G) 93 { 94 int u = it.u; 95 int v = it.v; 96 if(same(u, v)) continue; 97 mix(u, v); 98 inMST[mp[make_pair(u, v)]] = true; 99 addedge(u, v, it.w); 100 addedge(v, u, it.w); 101 res += it.w; 102 } 103 return res; 104 } 105 106 int fa[maxn][DEG]; 107 int deg[maxn]; 108 109 inline void BFS(int root) 110 { 111 queue<int>q; 112 deg[root] = 0; 113 fa[root][0] = root; 114 q.push(root); 115 while(!q.empty()) 116 { 117 int tmp = q.front(); 118 q.pop(); 119 for(int i = 1; i < DEG; ++i) 120 { 121 dis[tmp][i] = max(dis[tmp][i - 1], dis[fa[tmp][i - 1]][i - 1]); 122 fa[tmp][i] = fa[fa[tmp][i - 1]][i - 1]; 123 } 124 for(int i = head[tmp]; ~i; i = edge[i].nxt) 125 { 126 int v = edge[i].to; 127 if(v == fa[tmp][0]) continue; 128 deg[v] = deg[tmp] + 1; 129 fa[v][0] = tmp; 130 int id = mp[make_pair(tmp, v)]; 131 dis[v][0] = G[id].w; 132 q.push(v); 133 } 134 } 135 } 136 137 inline int LCA(int u,int v) 138 { 139 int res = 0; 140 if(deg[u] > deg[v]) 141 swap(u, v); 142 int hu = deg[u], hv = deg[v]; 143 int tu = u, tv = v; 144 for(int det = hv - hu, i = 0; det; det >>= 1, ++i) 145 { 146 if(det & 1) 147 { 148 res = max(res, dis[tv][i]); 149 tv = fa[tv][i]; 150 } 151 } 152 if(tu == tv) return res; 153 for(int i = DEG - 1; i >= 0; --i) 154 { 155 if(fa[tu][i] == fa[tv][i]) continue; 156 res = max(res, max(dis[tu][i], dis[tv][i])); 157 tu = fa[tu][i]; 158 tv = fa[tv][i]; 159 } 160 res = max(res, max(dis[tu][0], dis[tv][0])); 161 return res; 162 } 163 164 int main() 165 { 166 while(~scanf("%d %d", &n , &m)) 167 { 168 Init(); 169 for(int i = 1; i <= m; ++i) 170 { 171 int u, v; 172 ll w; 173 scanf("%d %d %lld", &u, &v, &w); 174 G.push_back(node(u, v, w)); 175 } 176 ll ans = MST(); 177 BFS(1); 178 int q; 179 scanf("%d", &q); 180 while(q--) 181 { 182 int u, v; 183 scanf("%d %d", &u, &v); 184 int id = mp[make_pair(u, v)]; 185 ll w = G[id].w; 186 if(inMST[id]) 187 { 188 printf("%lld ", ans); 189 } 190 else 191 { 192 ll res = LCA(u, v); 193 printf("%lld ", ans + w - res); 194 } 195 } 196 } 197 return 0; 198 }
J - Jumping frog
题意:给出一个字符串,是一个圆圈,‘R‘ 代码岩石 ‘P‘ 代表池塘 有一只青蛙,随便从哪一个岩石出发,固定步数k,若能回到原来的位置,那么这个步数就是ok的,求有多少个步数是ok的
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 1e5 +10; 6 7 bool flag[maxn]; 8 char str[maxn]; 9 10 inline int gcd(int a, int b) 11 { 12 return b == 0? a : gcd(b, a % b); 13 } 14 15 int main() 16 { 17 while(~scanf("%s", str)) 18 { 19 memset(flag, false, sizeof flag); 20 int n = strlen(str); 21 for(int i = 1; i < n; ++i) 22 { 23 if(n % i != 0) continue; 24 for(int j = 0; j < i; ++j) 25 { 26 bool tmp = true; 27 for(int k = 0; k <= n / i; ++k) 28 { 29 if(str[(j + k * i) % n] == ‘P‘) 30 { 31 tmp = false; 32 break; 33 } 34 } 35 if(tmp) 36 { 37 flag[i] = true; 38 break; 39 } 40 } 41 } 42 int ans = 0; 43 for(int i = 1; i < n; ++i) 44 { 45 if(flag[gcd(i, n)]) ans++; 46 } 47 printf("%d ", ans); 48 } 49 return 0; 50 }
K - Keep it covered
留坑。
L - Linearville
留坑。
M - Marblecoin
留坑。
以上是关于2017-2018 ACM-ICPC Latin American Regional Programming Contest Solution的主要内容,如果未能解决你的问题,请参考以下文章
2017-2018 ACM-ICPC Latin American Regional Programming Contest GYM101889
2017-2018 ACM-ICPC Latin American Regional Programming Contest Solution
2019-2020 ACM-ICPC Latin American Regional Programming Contest L - Leverage MDT
2019-2020 ACM-ICPC Latin American Regional Programming Contest A- Algorithm Teaching 二分图
2019-2020 ACM-ICPC Latin American Regional Programming Contest I - Improve SPAM 树形dp?