Codeforces Educational Codeforces Round 54 题解
Posted scaulok
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Educational Codeforces Round 54 题解相关的知识,希望对你有一定的参考价值。
题目链接: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 }
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 ",ans); 64 return 0; 65 }
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 }
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 ",min(n - 1,k)); 86 mst(vis, false); 87 dfs(1); 88 return 0; 89 }
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 }
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 }
G. Array Game(待补)
题意:
题解:
以上是关于Codeforces Educational Codeforces Round 54 题解的主要内容,如果未能解决你的问题,请参考以下文章
Educational Codeforces Round 37 B Tea Queue
Codeforces Educational Codeforces Round 67
Educational Codeforces Round 7 B
Educational Codeforces Round 7 A