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

 

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

 

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

 

 

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

 

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

 

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

 

 

 

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

 

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

 

 

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

 

 

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

 

posted @ 2019-02-27 20:18  Dup4  阅读(366)  评论(0编辑  收藏  举报