2018-2019 Всероссийская командная олимпиада школьников по программированию, интернет-тур + отборы регионов (ВКОШП 18, интернет-тур) Solution

A:

水。

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 typedef long long ll;
 6 
 7 const ll INFLL = 0x3f3f3f3f3f3f3f3f;
 8 
 9 ll n, m, h, w;
10 
11 ll solve()
12 {
13     ll cnt = 0;
14     ll tn = n, tm = m;
15     while(tn > h)
16     {
17         tn = (tn + 1)  >> 1;
18         cnt++;
19     }
20     while(tm > w)
21     {
22         tm = (tm + 1) >> 1;
23         cnt++;
24     }
25     return cnt;
26 }
27 
28 int main()
29 {
30     while(~scanf("%lld %lld %lld %lld", &n, &m, &h, &w))
31     {
32         ll ans = INFLL;
33         ans = min(ans, solve());
34         swap(h, w);
35         ans = min(ans, solve());
36         printf("%lld\n", ans);
37     }
38     return 0;
39 }
View Code

 

B:留坑。

 

C:

 

题意:有n道题目,总时间为T,对于每一道题目有完成的时间和可以得到的分数,做题策略为按照一定顺序做题,如果时间足够,那么就可以得到这道题的分数,安排一个顺序,使得得到的分数最少

思路:如果总时间<=T 那么直接输出所有分数

反之 ,考虑一定存在至少一道题目恰好不能被完成

枚举这道题目,考虑所有时间小于这道题目的所有题目都要被完成

对于每道题目,还需要枚举剩下的时间,使得它完不成

那么排序之后枚举,左边的题目都要做完,右边的做01背包

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define ll long long
 5 #define N 2010
 6 #define pll pair <ll, ll> 
 7 #define INF 0x3f3f3f3f3f3f3f3f
 8 int n, m;
 9 pll a[N];
10 ll dp[N][N];
11 ll tot_time, tot_sco;
12 
13 int main()
14 {
15     while (scanf("%d%d", &n, &m) != EOF)
16     {
17         tot_time = 0, tot_sco = 0;
18         for (int i = 1; i <= n; ++i) 
19         {
20             scanf("%lld%lld", &a[i].first, &a[i].second);
21             tot_time += a[i].first;
22             tot_sco += a[i].second;
23         }
24         if (tot_time <= m)
25         {
26             printf("%lld\n", tot_sco);
27             continue;
28         }
29         sort(a + 1, a + 1 + n);
30         memset(dp, 0x3f, sizeof dp);    
31         dp[n + 1][0] = 0;
32         for (int i = n; i > 1; --i)
33         { 
34             for (int j = m; j >= a[i].first; --j)
35                 dp[i][j] = min(dp[i][j], dp[i + 1][j - a[i].first] + a[i].second);
36             for (int j = 0; j <= m; ++j) dp[i][j] = min(dp[i][j], dp[i + 1][j]);
37         }
38         ll step = 0, tot = 0, res = INF;
39         for (int i = 1; i <= n; ++i)
40         {
41             ll tmp = INF;
42             for (int j = m - step; j + a[i].first + step > m && j >= 0; --j) tmp = min(tmp, tot + dp[i + 1][j]);
43             res = min(tmp, res); 
44             step += a[i].first;
45             tot += a[i].second;
46         }
47         printf("%lld\n", res);
48     }
49     return 0;
50 }
View Code

 

D:

题意:给出一棵树中每个点的度数,构造这一棵树

思路:将点按度数从大到小排序,每个点会有一个父亲,最多连出n - 1个点。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define N 200010
 5 #define pii pair <int, int>
 6 int n, d[N], pos[N], fa[N]; 
 7 
 8 bool cmp (int a, int b) { return d[a] > d[b]; }
 9 
10 int main()
11 {
12     while (scanf("%d", &n) != EOF)
13     {
14         for (int i = 1; i <= n; ++i) scanf("%d", d + i), pos[i] = i; 
15         sort(pos + 1, pos + 1 + n, cmp);
16         for (int i = 2; i <= n; ++i) --d[pos[i]];
17         int id = 1;
18         for (int i = 1; i <= n; ++i)
19         {
20             while (d[pos[i]]--) 
21                 fa[pos[++id]] = pos[i];   
22         }
23         for (int i = 1; i <= n; ++i) if (i != pos[1])
24             printf("%d %d\n", fa[i], i);    
25     }
26     return 0;
27 }
View Code

 

E:

水。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define ll long long
 5 #define N 1000010
 6 char s[N];
 7 
 8 int main()
 9 {
10     while (scanf("%s", s + 1) != EOF)
11     {
12         int cnt = 0;
13         for (int i = 1, len = strlen(s + 1); i <= len; ++i) cnt += (s[i] == 'A');
14         ll res = 0;
15         for (ll i = 1; ; ++i)
16         {
17             if (i * (i + 1) / 2 > cnt) break;
18             res = i;
19         }
20         printf("%lld\n", res);
21     }
22     return 0;
23 }
View Code

 

F:留坑。

 

G:

题意:给出一个n 要构造一个长度为n的序列,满足题目要求

思路:

如果是奇数

那么存在 起始点3   有 $2 \cdot 5 \cdot 6 = 3 \cdot 4 \cdot 5$

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 int n;
 5 
 6 int main()
 7 {
 8     while (scanf("%d", &n) != EOF)
 9     {
10         if (n == 1) puts("NO");
11         else if (n & 1) 
12         {
13             puts("YES");
14             puts("3"); 
15             printf("-++");
16             for (int i = 4; i <= n; ++i) printf("%c", "+-"[i & 1]);
17             puts("");
18         }
19         else
20         {
21             puts("YES");
22             puts("1");
23             for (int i = 1; i <= n; ++i) printf("%c", "-+"[i & 1]);
24             puts("");
25         }
26     }
27     return 0;
28 }
View Code

 

H:

题意:给出0-9每个数字的个数,构造一个最大的数,使得任意连续三位连起来都是3的倍数。数字可以不用完

思路:先将所有数字模3

就是三种数字 0, 1, 2

再考虑 排列

显然 三个一组三个一组,三个中012至少出现一次,即012的全排列,一共6种,

再考虑 全放0, 1, 2 又是三种

再考虑 只有一位或者两位,可以任意摆放  

一共十种情况,去掉前导0之后取最大即可。

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 
  4 #define N 100010
  5 int cnt[15], tmp_cnt[15], cntt[3], tmp_cntt[3], tar[3], Max[3], tmp_Max[3]; 
  6 char ans[10][N];     
  7 int pos;   
  8 
  9 void g()
 10 {
 11     for (int i = 0; i < 15; ++i) tmp_cnt[i] = cnt[i];
 12     for (int i = 0; i < 3; ++i) 
 13     {
 14         tmp_cntt[i] = cntt[i];
 15         tmp_Max[i] = Max[i];
 16     } 
 17 } 
 18 
 19 void f()
 20 {
 21     for (int i = 0; i < 15; ++i) cnt[i] = tmp_cnt[i];
 22     for (int i = 0; i < 3; ++i)
 23     {
 24         cntt[i] = tmp_cntt[i];
 25         Max[i] = tmp_Max[i]; 
 26     }
 27 } 
 28 
 29 void solve(int ide, int *tar)  
 30 { 
 31     pos = 0;
 32     while (1)
 33     {
 34         for (int i = 0; i < 3; ++i)
 35         {
 36             int id = tar[i];
 37             if (!cntt[id]) 
 38                 return; 
 39             if (cnt[Max[id]] == 0) 
 40             {
 41                 Max[id] = -1;  
 42                 for (int i = 9; i >= 0; --i) if (i % 3 == id && cnt[i]) 
 43                 {
 44                     Max[id] = i; 
 45                     break; 
 46                 }
 47                 if (Max[id] == -1) return; 
 48             }
 49             ans[ide][++pos] = Max[id] + '0';   
 50             --cntt[id]; 
 51             --cnt[Max[id]];  
 52         }
 53     }
 54 }
 55 
 56 void work(int id)
 57 {
 58     pos = 0; 
 59     while (cntt[id])
 60     {
 61         if (!cnt[Max[id]]) 
 62         {
 63             Max[id] = -1;
 64             for (int i = 9; i >= 0; --i) if (i % 3 == id && cnt[i])
 65             {
 66                 Max[id] = i;
 67                 break;    
 68             }
 69             if (Max[id] == -1) return;    
 70         }
 71         ans[id + 6][++pos] = Max[id] + '0';
 72         --cnt[Max[id]];
 73         --cntt[id];
 74     }
 75 }
 76 
 77 bool cmp(char *a, char *b) 
 78 {
 79     int lena = strlen(a + 1), lenb = strlen(b + 1);
 80     if (lena != lenb) return lena < lenb;
 81     for (int i = 1; i <= lena; ++i) if (a[i] != b[i])
 82         return a[i] < b[i];
 83     return 1;
 84 }
 85 
 86 void cle(int id)
 87 {
 88     int len = strlen(ans[id] + 1);
 89     pos = len + 1;
 90     for (int i = 1, len = strlen(ans[id] + 1); i <= len; ++i) if (ans[id][i] != '0')
 91     {
 92         pos = i;
 93         break;
 94     }
 95     if (pos == len + 1) 
 96     {
 97         ans[id][1] = '0';
 98         ans[id][2] = 0;
 99     }
100     else
101     {
102         for (int i = 1; i + pos - 1 <= len; ++i)
103             ans[id][i] = ans[id][i + pos - 1];
104         ans[id][len - pos + 2] = 0;
105     }
106 }
107 
108 int main()
109 {
110     while (scanf("%d", cnt) != EOF)
111     {
112         memset(cntt, 0, sizeof cntt); 
113         memset(Max, -1, sizeof Max);
114         memset(ans, 0, sizeof ans); 
115         for (int i = 1; i <= 9; ++i) scanf("%d", cnt + i);
116         for (int i = 0; i < 10; ++i) if (cnt[i])
117         {
118             cntt[i % 3] += cnt[i];
119             Max[i % 3] = i; 
120         } 
121         int res = 0;  
122         for (int i = 9; i >= 0 && res < 10; --i) if (cnt[i])
123         {
124             res = res * 10 + i;
125             if (res < 10 && cnt[i] > 1)
126                 res = res * 10 + i; 
127         } 
128         g(); 
129         pos = 0; 
130         while (res)
131         {
132             ans[9][++pos] = res % 10 + '0';  
133             res /= 10;
134         } 
135         ans[9][pos + 1] = 0; 
136         reverse(ans[9] + 1, ans[9] + pos + 1);  
137         tar[0] = 0, tar[1] = 1, tar[2] = 2;  
138         int ide = 0;
139         do
140         {
141             f();
142             solve(ide, tar); ans[ide][pos + 1] = 0; 
143             ++ide; 
144         } while (next_permutation(tar, tar + 3)); 
145         for (int i = 0; i < 3; ++i)
146         {
147             f(); pos = 0; work(i); 
148             ans[i + 6][pos + 1] = 0;  
149         } 
150         for (int i = 0; i < 10; ++i) cle(i);
151         pos = 0; 
152         for (int i = 1; i < 10; ++i) if (cmp(ans[pos], ans[i]))
153             pos = i;   
154         printf("%s\n", ans[pos] + 1); 
155     } 
156     return 0;
157 }
View Code

 

 

I:

题意:阅读理解题。有一个类似游泳圈的东西,有四道大道路,内圈,外圈,上圈,下圈,每个国家有四个城市,四个城市分别属于四道大道路上,定义经过一个国家为至少经过一条该国家的道路,有从任意一个国家的内城市出发,经过所有城市的最短路径

思路:考虑两种走法,

一种是两个国家之间都走内圈,还有一种是间隔走,走一下内圈,走一下上圈,取Min

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define ll long long
 5 const double PI = acos(-1.0);
 6 ll r, R, n;
 7 
 8 int main()
 9 {
10     while (scanf("%lld%lld%lld", &r, &R, &n) != EOF)
11     {
12         if (n == 1) 
13         {
14             printf("%.15f\n", PI * r / 2);
15             continue;
16         }
17         double len1 = (R - r) * 2.0 * PI / n; 
18         double len2 = R * 2.0 * PI / n;
19         double ans1 = (2 * n - 1) * PI * r / 2 + (n - 1) * len1;
20         double ans2 = n * PI * r / 2 + (n / 2) * len2 + ((n - 1) / 2) * len1;
21         printf("%.15f\n", min(ans1, ans2));
22     }
23     return 0;
24 }
View Code

 

J:留坑。

 

k:留坑。

 

L:水。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define ll long long
 5 #define N 1010
 6 int n, k, x, cnt; 
 7 char s[15];
 8 ll Bit[15];
 9 
10 ll f(char *s)
11 {
12     ll res = 0;
13     for (int i = 1, len = strlen(s + 1); i <= len; ++i)
14         res = res * 10 + s[i] - '0';
15     return res;
16 }
17 
18 int main()
19 {
20     Bit[1] = 1;
21     for (int i = 2; i <= 10; ++i) Bit[i] = Bit[i - 1] * 10;
22     while (scanf("%d", &n) != EOF)
23     {
24         cnt = 0; ll Min = 0;
25         for (int i = 1; i <= n; ++i) 
26         {
27             scanf("%s", s + 1);
28             cnt = max(cnt, (int)strlen(s + 1));
29             Min = max(Min, f(s)); 
30         }
31         Min = max((ll)n, Min); 
32         Min = max(Min, Bit[cnt]); 
33         printf("%lld\n", Min);
34         for (int i = 1; i <= cnt; ++i) putchar('9'); putchar('\n');
35     }
36     return 0;
37 }
View Code

 

posted @ 2018-11-11 18:15  Dup4  阅读(1010)  评论(0编辑  收藏  举报