2018-2019 Russia Open High School Programming Contest
A. Company Merging
Solved.
温暖的签到。
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 2e5 + 10; 6 7 typedef long long ll; 8 9 struct node{ 10 int val, num; 11 node(){} 12 node(int val, int num):val(val), num(num){} 13 }arr[maxn]; 14 15 int n, m; 16 17 int main() 18 { 19 while(~scanf("%d", &n)) 20 { 21 int Max = 0; 22 for(int i = 1; i <= n; ++i) 23 { 24 scanf("%d", &arr[i].num); 25 arr[i].val = 0; 26 for(int j = 1, x; j <= arr[i].num; ++j) 27 { 28 scanf("%d", &x); 29 arr[i].val = max(arr[i].val, x); 30 } 31 Max = max(arr[i].val, Max); 32 } 33 ll ans = 0; 34 for(int i = 1; i <= n; ++i) 35 { 36 // cout << arr[i].val << " " << endl; 37 ans += 1ll * arr[i].num * (Max - arr[i].val); 38 } 39 printf("%lld\n", ans); 40 } 41 return 0; 42 }
B. LaTeX Expert
Solved.
按题意模拟即可。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 100010 5 string str, s; 6 string st = "\\begin{thebibliography}{99}"; 7 string ed = "\\end{thebibliography}"; 8 map <string, int> mp; 9 int cnt, now; bool same; 10 string res[N]; 11 12 int getid(string s) 13 { 14 if (mp.find(s) == mp.end()) mp[s] = ++cnt; 15 return mp[s]; 16 } 17 18 void work() 19 { 20 int len = str.size(); 21 string tmp = ""; bool add = 0; 22 for (int i = 0; i < len; ++i) 23 { 24 if (str[i] == '{') add = 1; 25 else if (str[i] == '}') 26 { 27 getid(tmp); 28 tmp = ""; 29 add = 0; 30 } 31 else if (add) tmp += str[i]; 32 } 33 } 34 35 void add() 36 { 37 int len = s.size(); 38 string tmp = ""; bool add = 0; 39 for (int i = 0; i < len; ++i) 40 { 41 if (s[i] == '{') add = 1; 42 else if (s[i] == '}') 43 { 44 ++now; 45 int id = getid(tmp); 46 if (id != now) same = false; 47 res[id] = s; 48 return; 49 } 50 else if (add) 51 tmp += s[i]; 52 } 53 } 54 55 int main() 56 { 57 ios::sync_with_stdio(false); 58 cin.tie(0); cout.tie(0); 59 cnt = 0; now = 0; 60 bool start = 0; 61 same = true; 62 str = ""; 63 while (getline(cin, s)) 64 { 65 if (s == "") continue; 66 if (s == st) 67 { 68 start = 1; 69 work(); 70 continue; 71 } 72 if (s == ed) 73 { 74 if (same) 75 { 76 cout << "Correct\n"; 77 return 0; 78 } 79 cout << "Incorrect\n"; 80 cout << st << "\n"; 81 for (int i = 1; i <= cnt; ++i) 82 cout << res[i] << "\n"; 83 cout << ed << "\n"; 84 } 85 if (start) 86 add(); 87 else 88 str += s; 89 } 90 return 0; 91 }
C. New Year Presents
Upsolved.
题意:
有$n$个小朋友,每个小朋友有$s_i$件不同的物品,一个小朋友可以将自己的一件物品给另一个小朋友,前提是另一个小朋友没有这件物品,这样记为一次转移
求最少的转移次数使得拥有最多数量物品的小朋友和拥有最少数量物品的小朋友他们拥有的物品数量差值不超过1.
思路:
首先拥有东西多的小朋友肯定能往拥有东西少的小朋友转移(根据鸽笼原理),那只要把物品多的小朋友放在一起,然后去转移给物品少的小朋友就好了
注意枚举的技巧,复杂度应该跟$O(n)有关?$
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 100010 5 struct node 6 { 7 int l, r, x; 8 node () {} 9 node (int l, int r, int x) : l(l), r(r), x(x) {} 10 }; 11 vector <int> vec[N]; 12 int n, m; 13 int vis[N]; 14 vector <node> res; 15 int a[N * 100], now[N], nx[N * 100], last; 16 int sze[N]; 17 queue <int> q; 18 19 void add(int x, int id) 20 { 21 a[++last] = x; 22 nx[last] = now[id]; 23 now[id] = last; 24 } 25 26 int main() 27 { 28 while (scanf("%d%d", &n, &m) != EOF) 29 { 30 int tot = 0; 31 res.clear(); 32 memset(now, 0, sizeof now); 33 for (int i = 1, x, y; i <= n; ++i) 34 { 35 scanf("%d", &x); 36 tot += x; 37 vec[i].clear(); 38 for (int j = 1; j <= x; ++j) 39 { 40 scanf("%d", &y); 41 vec[i].push_back(y); 42 } 43 sze[i] = vec[i].size(); 44 } 45 if (tot % n == 0) 46 { 47 int x = tot / n; 48 for (int i = 1; i <= n; ++i) 49 if (sze[i] > x) 50 for (auto it : vec[i]) 51 add(i, it); 52 for (int i = 1; i <= m; ++i) 53 if (now[i]) q.push(i); 54 for (int i = 1, front; i <= n; ++i) 55 if (sze[i] < x) 56 { 57 for (auto it : vec[i]) 58 vis[it] = 1; 59 while (sze[i] < x) 60 { 61 front = q.front(); q.pop(); 62 //printf("%d %d %d\n", i, sze[i], front); 63 if (vis[front]) 64 { 65 q.push(front); 66 continue; 67 } 68 int id = now[front]; 69 for (; id ; id = nx[id]) 70 { 71 if (sze[a[id]] <= x) continue; 72 res.push_back(node(a[id], i, front)); 73 vec[i].push_back(front); 74 vis[front] = 1; 75 --sze[a[id]]; 76 ++sze[i]; 77 id = nx[id]; 78 break; 79 } 80 if (id) q.push(front); 81 now[front] = id; 82 } 83 for (auto it : vec[i]) 84 vis[it] = 0; 85 } 86 } 87 else 88 { 89 int x = tot / n + 1; 90 int need = n - tot % n; 91 for (int i = 1; i <= n; ++i) 92 if (sze[i] > x) 93 for (auto it : vec[i]) 94 add(i, it); 95 for (int i = 1; i <= m; ++i) 96 if (now[i]) q.push(i); 97 for (int i = 1, front; i <= n; ++i) 98 if (sze[i] < x) 99 { 100 if (sze[i] == x - 1 && need) 101 { 102 --need; 103 continue; 104 } 105 for (auto it : vec[i]) 106 vis[it] = 1; 107 while (sze[i] < x) 108 { 109 if (sze[i] == x - 1 && need) 110 { 111 --need; 112 break; 113 } 114 front = q.front(); q.pop(); 115 if (vis[front]) 116 { 117 q.push(front); 118 continue; 119 } 120 int id = now[front]; 121 for (; id; id = nx[id]) 122 { 123 if (sze[a[id]] <= x) continue; 124 res.push_back(node(a[id], i, front)); 125 vec[i].push_back(front); 126 vis[front] = 1; 127 --sze[a[id]]; 128 ++sze[i]; 129 id = nx[id]; 130 break; 131 } 132 if (id) q.push(front); 133 now[front] = id; 134 } 135 for (auto it : vec[i]) 136 vis[it] = 0; 137 } 138 } 139 int len = res.size(); 140 printf("%d\n", len); 141 for (int i = 0; i < len; ++i) 142 printf("%d %d %d\n", res[i].l, res[i].r, res[i].x); 143 } 144 return 0; 145 }
D. Similar Arrays
Solved.
找到一组没有任何关系的$i, j$填上1/1, 1/2, 其他的分别填入3-n。
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 1e5 + 10; 6 7 int n, m; 8 set<int>s[maxn]; 9 int arr[maxn], brr[maxn]; 10 11 void solve() 12 { 13 for(int i = 1; i <= n; ++i) 14 { 15 for(int j = i + 1; j <= n; ++j) if(s[i].count(j) == 0) 16 { 17 arr[i] = 1, arr[j] = 2; 18 brr[i] = 1, brr[j] = 1; 19 int pos = 3; 20 for(int k = 1; k <= n; ++k)if(!arr[k]) 21 { 22 arr[k] = brr[k] = pos++; 23 } 24 puts("YES"); 25 for(int k = 1; k <= n; ++k) printf("%d%c", arr[k], " \n"[k == n]); 26 for(int k = 1; k <= n; ++k) printf("%d%c", brr[k], " \n"[k == n]); 27 return ; 28 } 29 } 30 puts("NO"); 31 } 32 33 int main() 34 { 35 while(~scanf("%d %d", &n, &m)) 36 { 37 for(int i = 1; i <= n; ++i) s[i].clear(), arr[i] = brr[i] = 0; 38 for(int i = 1, l, r; i <= m; ++i) 39 { 40 scanf("%d %d", &l, &r); 41 s[min(l, r)].insert(max(l, r)); 42 } 43 solve(); 44 } 45 return 0; 46 }
E. Horseback Riding
Solved.
枚举每个终点, 跑一边$BFS$, 暴力搜索, 记录状态。
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 1e2 + 10; 6 7 int n; 8 vector<pair<int, int> >ans; 9 char str[maxn]; 10 int vis[maxn]; 11 int dis[maxn]; 12 int pre[maxn]; 13 int dir[8][2] = {1, 2, 1, -2, -1, 2, -1, -2, 2, 1, 2, -1, -2, 1, -2, -1}; 14 15 bool judge(int x, int y) 16 { 17 if(x < 0 || x >= 8 || y < 0 || y >= 8 || dis[x * 8 + y]) return false; 18 else return true; 19 } 20 21 void BFS(int st) 22 { 23 memset(dis, 0, sizeof dis); 24 memset(pre, -1, sizeof pre); 25 queue<int>q; 26 q.push(st); 27 dis[st] = 1; 28 while(!q.empty()) 29 { 30 int x = q.front() / 8; 31 int y = q.front() % 8; 32 q.pop(); 33 for(int j = 0; j < 8; ++j) 34 { 35 int dx = x + dir[j][0]; 36 int dy = y + dir[j][1]; 37 if(judge(dx, dy)) 38 { 39 dis[dx * 8 + dy] = dis[x * 8 + y] + 1; 40 pre[dx * 8 + dy] = x * 8 + y; 41 q.push(dx * 8 + dy); 42 } 43 } 44 } 45 } 46 47 int main() 48 { 49 while(~scanf("%d", &n)) 50 { 51 memset(vis, 0, sizeof vis); 52 ans.clear(); 53 for(int i = 1; i <= n; ++i) 54 { 55 scanf("%s", str); 56 vis[(str[1] - '1') * 8 + str[0] - 'a'] = 1; 57 } 58 ans.clear(); 59 for(int i = 0; i < n; ++i) 60 { 61 BFS(i); 62 int ed = i; 63 while(!vis[ed]) ++ed; 64 vis[ed] = 0; 65 while(ed != i) 66 { 67 vector<int>path; 68 do{ 69 path.push_back(ed); 70 ed = pre[ed]; 71 }while(vis[ed]); 72 path.push_back(ed); 73 for(int j = path.size() - 1; j >= 1; --j) ans.push_back(make_pair(path[j - 1], path[j])); 74 } 75 vis[ed] = 1; 76 } 77 int len = ans.size(); 78 printf("%d\n", len); 79 for(auto it : ans) 80 { 81 printf("%c%d-%c%d\n", it.first % 8 + 'a', it.first / 8 + 1, it.second % 8 + 'a', it.second / 8 + 1); 82 } 83 } 84 return 0; 85 }
F. How to Learn You Score
Upsolved.
题意:
有$n$个数,每次可以询问三个数,返回这三个数的最大值+最小值的和,用不超过$4 \cdot n$次的询问求出这$n$个数是什么
思路:
考虑$4$个数的时候,一共有$4$种询问方式,将这四种询问方式得到的四个值取最大最小值加起来就是这四个值的和
那么五个数我们就得到任意四个数的和,我们令$sum_i$表示不包含第$i$个数的和
那么有
$a_i + sum_i = a_j + sum_j$
有
$a_1 + sum_1 = a_2 + sum_2 = a_3 + sum_3 = a_4 + sum_4 = a_5 + sum_5$
联立后有
$4 \cdot a_1 = \sum\nolimits_{i = 1}^{5} sum_i - 4 \cdot sum_1$
依次求出这五个数
然后考虑后面的数可以用前面已知的数通过四次询问推出
总的询问次数$4 \cdot n$
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 #define N 1010 6 int n; 7 ll a[N]; 8 9 void work(int l, int r) 10 { 11 int ord[6]; ll sum[6]; 12 for (int i = 1, j = l; i <= 5; ++i, ++j) 13 ord[i] = j; 14 //for (int i = 1; i <= 5; ++i) printf("%d%c", ord[i], " \n"[i == 5]); 15 for (int i = 1; i <= 5; ++i) 16 { 17 vector <ll> vec; 18 int id[5], id2[4]; 19 ll x; 20 for (int j = 1, k = 0; j <= 5; ++j) 21 if (i != j) 22 id[++k] = ord[j]; 23 //for (int j = 1; j <= 4; ++j) 24 // printf("%d%c", id[j], " \n"[j == 4]); 25 for (int j = 1; j <= 4; ++j) 26 { 27 for (int k = 1, o = 0; k <= 4; ++k) 28 if (j != k) 29 id2[++o] = id[k]; 30 printf("? "); 31 for (int k = 1; k <= 3; ++k) 32 printf("%d%c", id2[k], " \n"[k == 3]); 33 fflush(stdout); 34 scanf("%lld", &x); 35 vec.push_back(x); 36 } 37 sort(vec.begin(), vec.end()); 38 sum[i] = vec.end()[-1] + *vec.begin(); 39 } 40 //for (int i = 1; i <= 5; ++i) 41 // printf("%lld%c", sum[i], " \n"[i == 5]); 42 ll tot = 0; 43 for (int i = 1; i <= 5; ++i) 44 tot += sum[i]; 45 for (int i = 1; i <= 5; ++i) 46 { 47 //assert((4ll * sum[i] - tot) % 4 == 0); 48 a[l + i - 1] = -(4ll * sum[i] - tot) / 4; 49 } 50 } 51 52 ll get(int l, int r) 53 { 54 int id[6], id2[6]; 55 vector <ll> vec; 56 ll x; 57 for (int i = 1; i <= 4; ++i) 58 id[i] = i + l - 1; 59 for (int j = 1; j <= 4; ++j) 60 { 61 for (int k = 1, o = 0; k <= 4; ++k) 62 if (j != k) 63 id2[++o] = id[k]; 64 printf("? "); 65 for (int k = 1; k <= 3; ++k) 66 printf("%d%c", id2[k], " \n"[k == 3]); 67 fflush(stdout); 68 scanf("%lld", &x); 69 vec.push_back(x); 70 } 71 sort(vec.begin(), vec.end()); 72 return vec.end()[-1] + *vec.begin(); 73 } 74 75 int main() 76 { 77 while (scanf("%d", &n) != EOF) 78 { 79 work(1, 5); 80 for (int i = 6; i <= n; ++i) 81 { 82 ll tot = get(i - 3, i); 83 for (int j = i - 3; j < i; ++j) 84 tot -= a[j]; 85 a[i] = tot; 86 } 87 printf("! "); 88 for (int i = 1; i <= n; ++i) 89 printf("%lld%c", a[i], " \n"[i == n]); 90 fflush(stdout); 91 } 92 return 0; 93 }
I. Minimal Product
Solved.
题意:求一个序列$找一个最小的a_i \cdot a_j 并且满足i < j, a_i < a_j$
思路:
正着扫一遍维护最小值,倒着扫一遍维护最大值。
注意生成序列的时候的取模,要自然溢出,否则会爆ll
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 7 const ll MOD = 1ll << 32; 8 const ll INFLL = 5e18; 9 const int maxn = 1e7 + 10; 10 11 ll n, l, r; 12 ll arr[maxn]; 13 unsigned int x, y,z, b1, b2; 14 unsigned int brr[maxn]; 15 16 int main() 17 { 18 int t; 19 scanf("%d", &t); 20 while(t--) 21 { 22 scanf("%lld %lld %lld %u %u %u %u %u", &n, &l, &r, &x, &y, &z, &b1, &b2); 23 brr[1] = b1; 24 brr[2] = b2; 25 for(int i = 3; i <= n; ++i) brr[i] = (brr[i - 2] * x + brr[i - 1] * y + z); 26 for(int i = 1; i <= n; ++i) arr[i] = (brr[i] % (r - l + 1) + l); 27 int flag = 0; 28 ll ans = INFLL; 29 ll Max = -INFLL; 30 for(int i = n; i >= 1; --i) 31 { 32 if(arr[i] < Max) 33 { 34 flag = 1; 35 ans = min(ans, arr[i] * Max); 36 } 37 Max = max(Max, arr[i]); 38 } 39 ll Min = INFLL; 40 for(int i = 1; i <= n; ++i) 41 { 42 if(arr[i] > Min) 43 { 44 flag = 1; 45 ans = min(ans, arr[i] * Min); 46 } 47 Min = min(Min, arr[i]); 48 } 49 if(!flag) puts("IMPOSSIBLE"); 50 else printf("%lld\n", ans); 51 } 52 return 0; 53 }
K. Right Expansion Of The Mind
Solved.
分为s, t两个字符串讨论。
对于t字符串, 只要两个t字符串含有相同字母即可。
对于s字符串, 从后往前删除在t字符串中的字符, 知道找到一个不在t字符串中的字符, 那么另一个可以匹配的字符串, 前缀相同。
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 int n; 6 string s, t; 7 map<pair<string, int>, vector<int> >mp; 8 9 int main() 10 { 11 ios::sync_with_stdio(false); 12 cin.tie(0); cout.tie(0); 13 while(cin >> n) 14 { 15 mp.clear(); 16 for(int i = 1; i <= n; ++i) 17 { 18 cin >> s >> t; 19 int tmp = 0; 20 for(int j = 0, len = t.length(); j < len; ++j) tmp |= (1 << (t[j] - 'a')); 21 int len = s.length(); 22 for(int j = len - 1; j >= 0; --j) 23 { 24 if(tmp & (1 << (s[j] - 'a'))) s.erase(s.begin() + j); 25 else break; 26 } 27 mp[make_pair(s, tmp)].push_back(i); 28 } 29 int res = mp.size(); 30 cout << res << "\n"; 31 for(auto vec : mp) 32 { 33 int len = vec.second.size(); 34 cout << len; 35 for(auto it : vec.second) 36 { 37 cout << " " << it; 38 } 39 cout << "\n"; 40 } 41 } 42 return 0; 43 }
L. erland University
Solved.
二分答案。
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 7 const int INF = 0x3f3f3f3f; 8 9 ll t, n, a, b, k; 10 11 bool check(ll mid) 12 { 13 ll res = mid * k; 14 ll tmp = min(a, mid) * (n / 2 + n % 2) + min(b, mid) * (n / 2); 15 return res <= tmp; 16 } 17 18 int main() 19 { 20 while(~scanf("%lld %lld %lld %lld %lld", &t ,&n, &a, &b, &k)) 21 { 22 ll l = 0, r = t, res = 0; 23 while(r - l >= 0) 24 { 25 ll mid = (l + r) >> 1; 26 if(check(mid)) 27 { 28 l = mid + 1; 29 res = mid; 30 } 31 else 32 { 33 r = mid - 1; 34 } 35 } 36 printf("%lld\n", res); 37 } 38 return 0; 39 }
M. The Pleasant Walk
Solved.
温暖的签到。
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 1e5 + 10; 6 7 int n, k; 8 int dp[maxn]; 9 int arr[maxn]; 10 11 int main() 12 { 13 while(~scanf("%d %d", &n, &k)) 14 { 15 int ans = 0; 16 memset(dp, 0, sizeof dp); 17 for(int i = 1; i <= n; ++i) scanf("%d", arr + i); 18 for(int i = 1; i <= n; ++i) 19 { 20 dp[i] = 1; 21 if(arr[i] != arr[i - 1]) dp[i] = max(dp[i - 1] + 1, dp[i]); 22 ans = max(ans, dp[i]); 23 } 24 printf("%d\n", ans); 25 } 26 return 0; 27 }