2017-2018 ACM-ICPC Latin American Regional Programming Contest Solution
A - Arranging tiles
留坑。
B - Buggy ICPC
题意:给出一个字符串,然后有两条规则,如果打出一个辅音字母,直接接在原字符串后面,如果打出一个元音字母,那么接在原来的字符串后面之后再翻转整个字符串,在这两条规则之下,求有多少种打印给定字符串的方法
思路:如果第一个字符是辅音,那么答案为0
如果全是辅音或全是元音,那么答案为1
如果只有一个辅音,答案为len
否则是最中间两个元音中间的辅音字符个数+1
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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\n", work()); 64 } 65 return 0; 66 }
C - Complete Naebbirac's sequence
题意:可以有三种操作, 一种是可以加上一个数,一种是可以减去一个数,一种是可以改变一个数 使得所有数出现次数相同,只能有一个操作,如果不能完成,输出"*"
思路:记录出现次数最大的数以及出现次数最小的次数,加上一个数是在(n + 1) % k == 0的时候,减去一个数是在(n - 1) % k == 0的时候,判断一下即可(水)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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\n", 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\n", Mn); 61 continue; 62 } 63 --arr[Mn]; 64 } 65 ++arr[Mn]; 66 --arr[Mx]; 67 if(check()) 68 { 69 printf("-%d +%d\n", Mx, Mn); 70 continue; 71 } 72 printf("*\n"); 73 74 } 75 return 0; 76 }
D - Daunting device
留坑。
E - Enigma
题意:给出两个数,有一个数中某些位是空的,填充空的位,使得左边那个数能够整除右边的数,并且左边那个数最小
思路:记忆化搜索,枚举每一位的每一种状态,从小向大枚举保证自断续最小。记录到每个点的余数,如果访问过就不继续搜索。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 << "\n"; 77 } 78 else 79 { 80 cout << "*\n"; 81 } 82 } 83 return 0; 84 }
F - Fundraising
题意:每个人有两个值,以及一个权值,若两个人都能选出来,那么要么两个人的值都相同,或者某个人的两个值分别大于另一个人,求选出一些人使得权值和最大
思路:两个值都相同的先合并,然后按一维排序,另一维做最大上升子序列权值和
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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\n", query(m)); 82 } 83 return 0; 84 }
G - Gates of uncertainty
留坑。
H - Hard choice
水。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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\n", ans); 15 } 16 return 0; 17 }
I - Imperial roads
题意:给出一张图,然后询问给出一条边,求有这条边的最小生成树的权值和
思路:先求最小生成树,然后询问的边如果在最小生成树里面那么就是原来的权值和,否则在原来的最小生成树里面的加入一条边,形成个环,然后去掉这个环里面除了加入的边之外的边权最大的边
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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\n", ans); 189 } 190 else 191 { 192 ll res = LCA(u, v); 193 printf("%lld\n", ans + w - res); 194 } 195 } 196 } 197 return 0; 198 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 100010 5 #define M N * 30 6 typedef pair <int, int> pii; 7 8 struct Edge1 9 { 10 int u, v, w; 11 inline Edge1() {} 12 inline Edge1(int u, int v, int w) : u(u), v(v), w(w) {} 13 inline bool operator < (const Edge1 &r) const 14 { 15 return w < r.w; 16 } 17 }; 18 19 struct Edge2 20 { 21 int to, nx, w; 22 inline Edge2() {} 23 inline Edge2(int to, int nx, int w) : to(to), nx(nx), w(w) {} 24 }edge[N << 1]; 25 26 vector <Edge1> vec; 27 map <pii, bool> mp; 28 map <pii, int> MP; 29 int n, m, q; 30 int pre[N]; 31 int head[N], pos; 32 int MST; 33 int rmq[N << 1], F[N << 1], P[N], cnt; 34 int T[N], L[M], R[M], C[M], tot; 35 36 struct ST 37 { 38 int mm[N << 1]; 39 int dp[N << 1][20]; 40 inline void init(int n) 41 { 42 mm[0] = -1; 43 for (int i = 1; i <= n; ++i) 44 { 45 mm[i] = ((i & (i - 1)) == 0) ? mm[i - 1] + 1 : mm[i - 1]; 46 dp[i][0] = i; 47 } 48 for (int j = 1; j <= mm[n]; ++j) 49 { 50 for (int i = 1; i + (1 << j) - 1 <= n; ++i) 51 { 52 dp[i][j] = rmq[dp[i][j - 1]] < rmq[dp[i + (1 << (j - 1))][j - 1]] ? dp[i][j - 1] : dp[i + (1 << (j - 1))][j - 1]; 53 } 54 } 55 } 56 inline int query(int a, int b) 57 { 58 if (a > b) swap(a, b); 59 int k = mm[b - a + 1]; 60 return rmq[dp[a][k]] <= rmq[dp[b - (1 << k) + 1][k]] ? dp[a][k] : dp[b - (1 << k) + 1][k]; 61 } 62 }st; 63 64 inline void Init() 65 { 66 for (int i = 1; i <= n; ++i) pre[i] = i; 67 memset(head, -1, sizeof head); 68 vec.clear(); mp.clear(); MP.clear(); 69 MST = 0; tot = 0, cnt = 0, pos = 0; 70 } 71 72 inline void addedge(int u, int v, int w) 73 { 74 edge[++pos] = Edge2(v, head[u], w); head[u] = pos; 75 } 76 77 inline int find(int x) 78 { 79 if (pre[x] != x) 80 pre[x] = find(pre[x]); 81 return pre[x]; 82 } 83 84 inline void join(int x, int y) 85 { 86 int fx = find(x), fy = find(y); 87 if (fx != fy) 88 pre[fx] = fy; 89 } 90 91 inline void Kruskal() 92 { 93 sort(vec.begin(), vec.end()); 94 int cnt = 1; 95 for (auto it : vec) 96 { 97 int u = it.u, v = it.v, w = it.w; 98 if (find(u) == find(v)) continue; 99 ++cnt; join(u, v); MST += w; 100 mp[pii(u, v)] = mp[pii(v, u)] = 1; 101 addedge(u, v, w); addedge(v, u, w); 102 if (cnt == n) break; 103 } 104 } 105 106 inline int build(int l, int r) 107 { 108 int root = tot++; 109 C[root] = 0; 110 if (l < r) 111 { 112 int mid = (l + r) >> 1; 113 L[root] = build(l, mid); 114 R[root] = build(mid + 1, r); 115 } 116 return root; 117 } 118 119 inline int update(int root, int pos) 120 { 121 int newroot = tot++, tmp = newroot; 122 C[newroot] = C[root] + 1; 123 int l = 1, r = 10000; 124 while (l < r) 125 { 126 int mid = (l + r) >> 1; 127 if (pos <= mid) 128 { 129 L[newroot] = tot++, R[newroot] = R[root]; 130 newroot = L[newroot], root = L[root]; 131 r = mid; 132 } 133 else 134 { 135 L[newroot] = L[root], R[newroot] = tot++; 136 newroot = R[newroot], root = R[root]; 137 l = mid + 1; 138 } 139 C[newroot] = C[root] + 1; 140 } 141 return tmp; 142 } 143 144 inline int query(int left_root, int right_root) 145 { 146 int l = 1, r = 10000; 147 while (l < r) 148 { 149 int mid = (l + r) >> 1; 150 int tot = C[R[left_root]] - C[R[right_root]]; 151 if (tot > 0) 152 { 153 left_root = R[left_root]; 154 right_root = R[right_root]; 155 l = mid + 1; 156 } 157 else 158 { 159 left_root = L[left_root]; 160 right_root = L[right_root]; 161 r = mid; 162 } 163 } 164 return l; 165 } 166 167 inline void DFS(int u, int pre, int dep) 168 { 169 F[++cnt] = u; 170 rmq[cnt] = dep; 171 P[u] = cnt; 172 for (int it = head[u]; ~it; it = edge[it].nx) 173 { 174 int v = edge[it].to; 175 if (v == pre) continue; 176 int w = edge[it].w; 177 T[v] = update(T[u], w); 178 DFS(v, u, dep + 1); 179 F[++cnt] = u; 180 rmq[cnt] = dep; 181 } 182 } 183 184 inline void LCA_init(int root, int node_num) 185 { 186 T[1] = build(1, 10000); 187 DFS(root, root, 0); 188 st.init(2 * node_num - 1); 189 } 190 191 inline int query_lca(int u, int v) 192 { 193 return F[st.query(P[u], P[v])]; 194 } 195 196 inline void Run() 197 { 198 while (scanf("%d%d", &n, &m) != EOF) 199 { 200 Init(); 201 for (int i = 1, u, v, w; i <= m; ++i) 202 { 203 scanf("%d%d%d", &u, &v, &w); 204 vec.emplace_back(u, v, w); 205 MP[pii(u, v)] = MP[pii(v, u)] = w; 206 } 207 Kruskal(); LCA_init(1, n); 208 scanf("%d", &q); 209 for (int i = 1, u, v; i <= q; ++i) 210 { 211 scanf("%d%d", &u, &v); 212 if (mp[pii(u, v)]) printf("%d\n", MST); 213 else 214 { 215 int lca = query_lca(u, v); 216 int Max = query(T[u], T[lca]); 217 Max = max(Max, query(T[v], T[lca])); 218 //printf("%d %d %d %d\n", u, v, lca, Max); 219 printf("%d\n", MST + MP[pii(u, v)] - Max); 220 } 221 } 222 } 223 } 224 225 int main() 226 { 227 #ifdef LOCAL 228 freopen("Test.in", "r", stdin); 229 #endif 230 231 Run(); 232 return 0; 233 }
J - Jumping frog
题意:给出一个字符串,是一个圆圈,'R' 代码岩石 'P' 代表池塘 有一只青蛙,随便从哪一个岩石出发,固定步数k,若能回到原来的位置,那么这个步数就是ok的,求有多少个步数是ok的
思路:如果一个步数k可以完成,那么前提为gcd(n, k)可行(可通过反证法证明)。枚举n的每个因子跑一边即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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\n", ans); 48 } 49 return 0; 50 }
K - Keep it covered
留坑。
L - Linearville
留坑。
M - Marblecoin
留坑。