A
•水
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define ri register int #define ll long long #define fast ios::sync_with_stdio(0), cin.tie(0), cout.tie(0) using namespace std; const inline int read(){ int k = 0, f = 1; char c = getchar(); for(;!isdigit(c); c = getchar()) if(c == '-') f = -1; for(;isdigit(c); c = getchar()) k = k * 10 + c - '0'; return k * f; } int t, h, m, ans; int main(){ t = read(); while(t--){ h = read(); m = read(); if(!h && !m) printf("0\n"); else{ ans = (23 - h) * 60 + (60 - m); printf("%d\n", ans); } } }
B
•先平分,有多余的在满足条件情况下尽量加进去
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define ri register int #define ll long long #define fast ios::sync_with_stdio(0), cin.tie(0), cout.tie(0) using namespace std; const inline int read(){ int k = 0, f = 1; char c = getchar(); for(;!isdigit(c); c = getchar()) if(c == '-') f = -1; for(;isdigit(c); c = getchar()) k = k * 10 + c - '0'; return k * f; } int t, n, k, ans = 0, up, q; int main(){ t = read(); while(t--){ ans = 0; n = read(), k = read(); up = (k >> 1); q = n % k; if(q < up) ans = n; else ans = n - (q - up); printf("%d\n", ans); } return 0; }
C
题意:将数组中的0换成未出现的数字,使数组成为1~n的错排
•统计没有出现的数字num(统计的时候已经默认升序了),然后倒序填入0的位置
•若填入时a[num] = num,如果是第一个填入就让当前num与下一个num互换,如果不是第一个填入则先填入,再将a[num]与上一次填入的a[num]交换即可(因为是倒序填入,所以交换后上一填入位置一定满足a[num] ≠ num
#include<bits/stdc++.h> #define ri register int #define ll long long #define fast ios::sync_with_stdio(0), cin.tie(0), cout.tie(0) using namespace std; const inline int read(){ int k = 0, f = 1; char c = getchar(); for(;!isdigit(c); c = getchar()) if(c == '-') f = -1; for(;isdigit(c); c = getchar()) k = k * 10 + c - '0'; return k * f; } int n, a[200010], b[200010], c[200010], cnt = 0, k; bool vis[200010]; int main(){ n = read(); memset(vis, false, sizeof(vis)); for(ri i = 1; i <= n; ++i){ a[i] = read(); vis[a[i]] = 1; } for(ri i = 1; i <= n ; ++i) if(!vis[i]) b[++cnt] = i; k = cnt; for(ri i = 1; i <= n; ++i) if(!a[i]){ if(i == b[cnt]){ if(cnt < k){ a[i] = b[cnt]; swap(a[i], a[c[cnt + 1]]); cnt--; } else{ int z = b[cnt]; b[cnt] = b[cnt - 1]; b[cnt - 1] = z; a[i] = b[cnt--]; } } else{ c[cnt] = i; a[i] = b[cnt--]; } } for(ri i = 1; i <= n; ++i) printf("%d ", a[i]); return 0; }
题意:使得人与树的距离之和最小
•贪心,优先选择距离树最近的点即可,相当于在一个数轴上一轮一轮进行bfs
#include<bits/stdc++.h> #define ri register int #define ll long long #define fast ios::sync_with_stdio(0), cin.tie(0), cout.tie(0) using namespace std; const inline int read(){ int k = 0, f = 1; char c = getchar(); for(;!isdigit(c); c = getchar()) if(c == '-') f = -1; for(;isdigit(c); c = getchar()) k = k * 10 + c - '0'; return k * f; } int n, m, x, a[200010], cnt = 0; long long ans = 0; map<int, int> mp; queue<int> q; int main(){ n = read(), m = read(); for(ri i = 1; i <= n; ++i){ x = read(); q.push(x); mp[x] = 0; } while(cnt < m){ int now = q.front(); q.pop(); if(!mp.count(now - 1)){ mp[now - 1] = mp[now] + 1; q.push(now - 1); } if(!mp.count(now + 1)){ mp[now + 1] = mp[now] + 1; q.push(now + 1); } if(mp[now] > 0){ a[++cnt] = now; ans += mp[now]; } } printf("%lld\n", ans); for(ri i = 1; i <= m - 1; ++i) printf("%d ", a[i]); printf("%d\n", a[m]); return 0; }
E
题意:一个数轴上有一群人,每个人初始位置xi,最终位置可以在xi - 1, xi, xi + 1上,求有人在的点数目的min与max
•贪心,先排序
•求min时,人尽可能聚在一起,从头开始安置每一个人,如果在xi - 1, xi, xi + 1有已经安置好的人,则不需要新的聚集点,否则在xi+1处创建新的聚集点(因为是升序安置,所以新聚集点尽可能靠右)
•求max时,人尽可能散开,从头开始安置每一个人,优先靠左安置,xi - 1, xi, xi + 1,选择可安置的点,若都已经安置有人则继续下一个人
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define ri register int #define ll long long #define fast ios::sync_with_stdio(0), cin.tie(0), cout.tie(0) using namespace std; const inline int read(){ int k = 0, f = 1; char c = getchar(); for(;!isdigit(c); c = getchar()) if(c == '-') f = -1; for(;isdigit(c); c = getchar()) k = k * 10 + c - '0'; return k * f; } #define maxn 200010 int n, a[maxn], vis[maxn], ans = 0; int main(){ n = read(); for(ri i = 1; i <= n; ++i) a[i] = read(); sort(a + 1, a + n + 1); for(ri i = 1; i <= n; ++i){ if(vis[a[i] - 1] || vis[a[i]] || vis[a[i] + 1]){ continue; } ans++; vis[a[i] + 1] = 1; } printf("%d ", ans); ans = 0; memset(vis, 0, sizeof(vis)); for(ri i = 1; i <= n; ++i){ if(!vis[a[i] - 1]){ ans++; vis[a[i] - 1] = 1; continue; } if(!vis[a[i]]){ ans++; vis[a[i]] = 1; continue; } if(!vis[a[i] + 1]){ ans++; vis[a[i] + 1] = 1; continue; } } printf("%d\n", ans); return 0; }
F
题意:n - 1个电线,n个灯,每条线两端分为主灯和辅灯,电从主灯流向辅灯,每个灯都有编号,亮度为2i,每个电线有一个重要值,它的重要值为间断该电线之后损失的灯泡亮度之和,已知每个电线的主灯编号,求每个电线两端的灯的编号
•n - 1个电线,n个灯,显然结构为树
•重要值最高的灯一个是树根
•用数组d记录每个主灯儿子节点的个数,没有儿子节点的点即为叶节点
•将叶节点放入小根堆中,每次堆顶与重要值最小的点连接,该主灯的儿子节点数 - 1
•主灯的儿子节点数为0时,自己就是叶节点了,放入堆中
#include<bits/stdc++.h> #define ri register int #define ll long long #define fast ios::sync_with_stdio(0), cin.tie(0), cout.tie(0) using namespace std; const inline int read(){ int k = 0, f = 1; char c = getchar(); for(;!isdigit(c); c = getchar()) if(c == '-') f = -1; for(;isdigit(c); c = getchar()) k = k * 10 + c - '0'; return k * f; } int n, d[200010], x, root; vector<int> fa; priority_queue<int, vector<int>, greater<int> > q; vector<pair<int, int> > ans; int main(){ n = read(); root = read(); d[root]++; fa.push_back(root); for(ri i = 2; i <= n - 1; ++i){ x = read(); d[x]++; fa.push_back(x); } for(ri i = 1; i <= n; ++i) if(!d[i]) q.push(i); while(!q.empty()){ int now = q.top(); q.pop(); int m = fa[fa.size() - 1]; fa.pop_back(); ans.push_back(make_pair(m, now)); if(ans.size() == n - 1) break; d[m]--; if(!d[m]) q.push(m); } printf("%d\n", root); for(ri i = ans.size() - 1; i >= 0; --i) printf("%d %d\n", ans[i].first, ans[i].second); return 0; }