Codeforces Educational Codeforces Round 54 题解

天涯浪子 提交于 2020-02-13 03:48:17

题目链接:https://codeforc.es/contest/1076

A. Minimizing the String

题意:给出一个字符串,最多删掉一个字母,输出操作后字典序最小的字符串。

题解:若存在一个位置 i 满足 a[i] > a[i+1],若不删除 a[i] 则后续操作不可能更优。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define ull unsigned long long
 5 #define mst(a,b) memset((a),(b),sizeof(a))
 6 #define mp(a,b) make_pair(a,b)
 7 #define pi acos(-1)
 8 #define pii pair<int,int>
 9 #define pb push_back
10 const int INF = 0x3f3f3f3f;
11 const double eps = 1e-6;
12 const int MAXN = 2e5 + 10;
13 const int MAXM = 2e5 + 10;
14 const ll mod = 1e9 + 7;
15 
16 char s[MAXN];
17 
18 int main() {
19 #ifdef local
20     freopen("data.txt", "r", stdin);
21 //    freopen("data.txt", "w", stdout);
22 #endif
23     int n;
24     scanf("%d%s",&n,s);
25     int pos = n - 1;
26     for(int i = 0; i < n - 1; i++) {
27         if(s[i] > s[i + 1]) {
28             pos = i;
29             break;
30         }
31     }
32     for(int i = 0; i < n; i++)
33         if(i != pos) printf("%c",s[i]);
34     return 0;
35 }
View Code

 

B. Divisor Subtraction

题意:对于一个 n,每次减去它的最小质因子直到为 0,求操作次数。

题解:n <= 1e10,所以先筛出 1e5 以内的质因子,然后暴力找最小质因子,当最小质因子为 2 的时候,已经不存在更小的质因子,直接跳出循环即可。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define ull unsigned long long
 5 #define mst(a,b) memset((a),(b),sizeof(a))
 6 #define mp(a,b) make_pair(a,b)
 7 #define pi acos(-1)
 8 #define pii pair<int,int>
 9 #define pb push_back
10 const int INF = 0x3f3f3f3f;
11 const double eps = 1e-6;
12 const int MAXN = 2e5 + 10;
13 const int MAXM = 2e5 + 10;
14 const ll mod = 1e9 + 7;
15 
16 bool check[MAXN];
17 int prime[MAXN];
18 int tot;
19 
20 void init() {
21     mst(check, false);
22     tot = 0;
23     for(int i = 2; i <= 1e5; i++) {
24         if(!check[i]) prime[tot++] = i;
25         for(int j = 0; j < tot; j++) {
26             if(i * prime[j] > 1e5) break;
27             check[i * prime[j]] = true;
28             if(i % prime[j] == 0) break;
29         }
30     }
31 }
32 
33 int main() {
34 #ifdef local
35     freopen("data.txt", "r", stdin);
36 //    freopen("data.txt", "w", stdout);
37 #endif
38     init();
39     ll n;
40     scanf("%lld",&n);
41     ll ans = 0;
42     while(n) {
43         bool flag = false;
44         for(int i = 0; i < tot && n >= prime[i]; i++) {
45             if(n % prime[i] == 0) {
46                 if(prime[i] == 2) {
47                     flag = true;
48                     ans += n / 2;
49                     n = 0;
50                     break;
51                 }
52                 n -= prime[i];
53                 ans++;
54                 flag = true;
55                 break;
56             }
57         }
58         if(!flag) {
59             ans++;
60             break;
61         }
62     }
63     printf("%lld\n",ans);
64     return 0;
65 }
View Code

 

C. Meme Problem

题意:给出一个 d,求是否存在 a + b = d 且 ab = d。

题解:解一元二次方程,判一下无解的条件即可。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define ull unsigned long long
 5 #define mst(a,b) memset((a),(b),sizeof(a))
 6 #define mp(a,b) make_pair(a,b)
 7 #define pi acos(-1)
 8 #define pii pair<int,int>
 9 #define pb push_back
10 const int INF = 0x3f3f3f3f;
11 const double eps = 1e-6;
12 const int MAXN = 2e5 + 10;
13 const int MAXM = 2e5 + 10;
14 const ll mod = 1e9 + 7;
15 
16 
17 
18 int main() {
19 #ifdef local
20     freopen("data.txt", "r", stdin);
21 //    freopen("data.txt", "w", stdout);
22 #endif
23     int t;
24     cin >> t;
25     while(t--) {
26         int d;
27         cin >> d;
28         if(d < 4 && d != 0) {
29             cout << "N" << endl;
30             continue;
31         }
32         cout << "Y ";
33         long double a = sqrt(((long double)d * d - 4.0 * (long double)d) / 4.0) + (long double)d / 2.0;
34         long double b = (long double)d - a;
35         cout << fixed << setprecision(10) << a << ' ';
36         cout << fixed << setprecision(10) << b << endl;
37     }
38     return 0;
39 }
View Code

 

D. Edge Deletion

题意:给出一个 n 个点 m 条边的图,问最多保留 k 条边的情况下,起点 1 到每个点的最短路不变的最多有多少个,输出保留的边。

题解:先对起点 1 跑一遍 dij,因为 n - 1 条边可以构成图的最短路,每条边产生对一个点的最短路,故跑 dij 时记录一下走当前这个点的边,跑 dfs 按顺序输出结果即可。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define ull unsigned long long
 5 #define mst(a,b) memset((a),(b),sizeof(a))
 6 #define mp(a,b) make_pair(a,b)
 7 #define pi acos(-1)
 8 #define pii pair<int,int>
 9 #define pb push_back
10 const int INF = 0x3f3f3f3f;
11 const double eps = 1e-6;
12 const int MAXN = 3e5 + 10;
13 const int MAXM = 2e5 + 10;
14 const ll mod = 1e9 + 7;
15 
16 
17 struct edge {
18     int v,w,id;
19 };
20 
21 vector<edge>g[MAXN];
22 bool vis[MAXN];
23 ll dis[MAXN];
24 vector<int>ans;
25 pii add[MAXN];
26 
27 void dij(int s, int n) {
28     ll inf2 = 1e16;
29     for(int i = 1; i <= n; ++i)
30         dis[i] = inf2, vis[i] = 0;
31     dis[s] = 0;
32     priority_queue<pair<ll, int> >q;
33     q.push(mp(0, s));
34     for(; !q.empty();) {
35         int u = q.top().second;
36         q.pop();
37         if(vis[u]) continue;
38         vis[u] = 1;
39         for(int j = 0, sz = g[u].size(); j < sz; ++j) {
40             int v = g[u][j].v;
41             int w = g[u][j].w;
42             int id = g[u][j].id;
43             if(dis[v] > dis[u] + w) {
44                 add[v] = mp(u,id);
45                 dis[v] = dis[u] + w;
46                 q.push(mp(-dis[v], v));
47             }
48         }
49     }
50 }
51 
52 vector<pii>vec[MAXN];
53 int tot;
54 
55 void dfs(int u) {
56     vis[u] = true;
57     for(int i = 0; i < vec[u].size() && tot; i++) {
58         int v = vec[u][i].first, id = vec[u][i].second;
59         if(vis[v]) continue;
60         printf("%d ",id);
61         tot--;
62         dfs(v);
63     }
64 }
65 
66 int main() {
67 #ifdef local
68     freopen("data.txt", "r", stdin);
69 //    freopen("data.txt", "w", stdout);
70 #endif
71     int n,m,k;
72     scanf("%d%d%d",&n,&m,&k);
73     for(int i = 1; i <= m; i++) {
74         int u,v,w;
75         scanf("%d%d%d",&u,&v,&w);
76         g[u].pb({v,w,i});
77         g[v].pb({u,w,i});
78     }
79     dij(1,n);
80     for(int i = 2; i <= n; i++) {
81         vec[i].push_back(mp(add[i].first,add[i].second));
82         vec[add[i].first].push_back(mp(i,add[i].second));
83     }
84     tot = min(n - 1,k);
85     printf("%d\n",min(n - 1,k));
86     mst(vis, false);
87     dfs(1);
88     return 0;
89 }
View Code

 

E. Vasya and a Tree

题意:有一棵 n 个点的树,有 m 次操作(v,d,x),每次将以 v 为根且距离 v <= d 的点加上权值 x(初始权值为0),输出最后每个点的权值。

题解:考虑离线操作,把每个点作为根的操作存起来,dfs 记录当前深度所增加的权值,对于不可到达的深度,用一个数组来记录要减去的值,差分的思想,详见代码~

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define ull unsigned long long
 5 #define mst(a,b) memset((a),(b),sizeof(a))
 6 #define mp(a,b) make_pair(a,b)
 7 #define pi acos(-1)
 8 #define pii pair<int,int>
 9 #define pb push_back
10 const int INF = 0x3f3f3f3f;
11 const double eps = 1e-6;
12 const int MAXN = 3e5 + 10;
13 const int MAXM = 2e5 + 10;
14 const ll mod = 1e9 + 7;
15 
16 vector<int>vec[MAXN];
17 vector<pii>q[MAXN];
18 
19 
20 int h = -1;
21 ll ans[MAXN],dep[MAXN],now = 0;
22 
23 void dfs(int u,int fa) {
24     h++;
25     now += dep[h];
26     for(int i = 0; i < q[u].size(); i++) {
27         int d = q[u][i].first, x = q[u][i].second;
28         now += x;
29         if(h + d + 1 < MAXN) dep[h + d + 1] -= x;
30     }
31 //    cout << u << " " << fa << ":" << now << endl;
32     ans[u] += now;
33     for(int i = 0; i < vec[u].size(); i++) {
34         int v = vec[u][i];
35         if(v == fa) continue;
36         dfs(v,u);
37     }
38     for(int i = 0; i < q[u].size(); i++) {
39         int d = q[u][i].first, x = q[u][i].second;
40         now -= x;
41         if(h + d + 1 < MAXN) dep[h + d + 1] += x;
42     }
43     now -= dep[h];
44     h--;
45 }
46 
47 int main() {
48 #ifdef local
49     freopen("data.txt", "r", stdin);
50 //    freopen("data.txt", "w", stdout);
51 #endif
52     int n;
53     scanf("%d",&n);
54     for(int i = 1; i < n; i++) {
55         int u,v;
56         scanf("%d%d",&u,&v);
57         vec[u].push_back(v);
58         vec[v].push_back(u);
59     }
60     int m;
61     scanf("%d",&m);
62     while(m--) {
63         int v,d,x;
64         scanf("%d%d%d",&v,&d,&x);
65         q[v].push_back(mp(d,x));
66     }
67     dfs(1,0);
68     for(int i = 1; i <= n; i++)
69         printf("%lld ",ans[i]);
70     return 0;
71 }
View Code

 

F. Summer Practice Report

题意:一本书有 n 页,每页有 xi 个 0 和 yi 个 1,问存不存在每页的数字构成一个序列,连起来之后最多连续的 0 和 1 不超过 k。

题解:记录每一页组成序列之后,连续 1 和连续 0 的最小值,转移即可。因为一页中连续的 1 最多 k 个,所以可容纳的 0 的个数为 pre0 + k * x,记录这个数是否大于 0 即可判断是否合法,1 也同理。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define ull unsigned long long
 5 #define mst(a,b) memset((a),(b),sizeof(a))
 6 #define mp(a,b) make_pair(a,b)
 7 #define pi acos(-1)
 8 #define pii pair<int,int>
 9 #define pb push_back
10 const int INF = 0x3f3f3f3f;
11 const double eps = 1e-6;
12 const int MAXN = 3e5 + 10;
13 const int MAXM = 2e5 + 10;
14 const ll mod = 1e9 + 7;
15 
16 ll x[MAXN],y[MAXN];
17 
18 int main() {
19 #ifdef local
20     freopen("data.txt", "r", stdin);
21 //    freopen("data.txt", "w", stdout);
22 #endif
23     int n;
24     ll k;
25     scanf("%d%lld",&n,&k);
26     for(int i = 1; i <= n; i++) scanf("%lld",&x[i]);
27     for(int i = 1; i <= n; i++) scanf("%lld",&y[i]);
28     ll nowx = -k, nowy = -k;
29     for(int i = 1; i <= n; i++) {
30         nowx += x[i] - y[i] * k;
31         nowy += y[i] - x[i] * k;
32         if(nowx < -k) nowx = -k;
33         if(nowy < -k) nowy = -k;
34         if(nowx > 0 || nowy > 0) {
35             puts("NO");
36             return 0;
37         }
38     }
39     puts("YES");
40     return 0;
41 }
View Code

 

G. Array Game(待补)

题意:

题解:

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!