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\n", work());
64     }
65     return 0;
66 }
View Code

 

C - Complete Naebbirac's sequence

题意:可以有三种操作, 一种是可以加上一个数,一种是可以减去一个数,一种是可以改变一个数 使得所有数出现次数相同,只能有一个操作,如果不能完成,输出"*"

思路:记录出现次数最大的数以及出现次数最小的次数,加上一个数是在(n + 1) % k == 0的时候,减去一个数是在(n - 1) % k == 0的时候,判断一下即可(水)

 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 }
View Code

 

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 << "\n";
77         }
78         else
79         {
80             cout << "*\n";
81         }
82     }
83     return 0;
84 }
View Code

 

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\n", query(m));
82     }
83     return 0;    
84 }
View Code

 

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\n", ans);
15     }
16     return 0;
17 }
View Code

 

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\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 }
View Code

 

  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 }
View Code

 

J - Jumping frog

题意:给出一个字符串,是一个圆圈,'R' 代码岩石 'P' 代表池塘 有一只青蛙,随便从哪一个岩石出发,固定步数k,若能回到原来的位置,那么这个步数就是ok的,求有多少个步数是ok的

思路:如果一个步数k可以完成,那么前提为gcd(n, k)可行(可通过反证法证明)。枚举n的每个因子跑一边即可。

 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 }
View Code

 

 

K - Keep it covered

留坑。

 

L - Linearville

留坑。

 

M - Marblecoin

留坑。

 

posted @ 2018-09-02 18:48  Dup4  阅读(850)  评论(0编辑  收藏  举报