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)) 6View Code#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 local20 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\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(待補)
題意:
題解:
Codeforces Educational Codeforces Round 54 題解