Codeforces Round #748 (Div. 3) 解题报告
CF1593A Elections
题意
三个人参加投票选举,分别得到了 \(a\) 票、 \(b\) 票和 \(c\) 票。求每个人至少还要得到多少票才能比另外两个人得到的票都多。(每个人需要多得到的票数独立计算,不会互相影响。)
思路
对于第一个人,检查 \(a\) 是否大于 \(\max\{b, c\}\),如果大于就不需要多得到投票,否则需要多得到 \(\max\{b, c\} - a + 1\) 票。(之所以要 +1
是因为必须比别人得票多而不是和别人得票相等。)
第二个人、第三个人同理。
代码
#include<iostream>
#include<algorithm>
using namespace std;
int main() {
int a, b, c, T;
cin >> T;
while(T--) {
cin >> a >> b >> c;
if(a > max(b, c)) {
cout << 0 << " ";
} else {
cout << max(b, c) - a + 1 << " ";
}
if(b > max(a, c)) {
cout << 0 << " ";
} else {
cout << max(a, c) - b + 1 << " ";
}
if(c > max(b, a)) {
cout << 0 << " ";
} else {
cout << max(b, a) - c + 1 << " ";
}
cout << endl;
}
return 0;
}
CF1593B Make it Divisible by 25
题意
输入一个正整数 \(n\),删去若干位数使其能被 25 整除,求最少要删去多少位数字。
数据范围:\(25 \leq n \leq 10^{18}\)
思路
25 的倍数的特征很简单:末尾两位数是 00、25、50、75,所以我们可以考虑进行贪心:
从最后一位出发,找到最低位的 0 和最低位的 5,记录为第 \(p\) 位和第 \(q\) 位。
然后再从第 \(p\) 位出发,向左找到遇到的第一个 0 或 5,将这两位后面的所有数都删去,更新答案;从第 \(q\) 位出发,向左找到遇到的第一个 2 或 7,将这两位后面的所有数都删去,更新答案。
代码
代码实现比较简单,但要注意细节。
#include<iostream>
using namespace std;
const int MAXN = 100 + 5;
int a[MAXN];
int len = 0;
int main() {
int T;
cin >> T;
while(T--) {
long long n;
cin >> n;
len = 0;
long long t = n;
while(t != 0) {
a[++len] = t % 10;
t /= 10;
}
int p = len, q = len, ans = len;
for(int i = len; i >= 1; i--) {
if(a[i] == 0) {
p = i;
} else if(a[i] == 5) {
q = i;
}
}
for(int i = p + 1; i <= len; i++) {
if(a[i] == 0 || a[i] == 5) {
ans = min(ans, i - 2);
}
}
for(int i = q + 1; i <= len; i++) {
if(a[i] == 2 || a[i] == 7) {
ans = min(ans, i - 2);
}
}
cout << ans << endl;
}
return 0;
}
CF1593C Save More Mice
题意
在数轴上有一只猫,\(k\) 只老鼠和一个洞,猫在点 \(0\),洞在点 \(n\),第 \(i\) 只老鼠在点 \(x_i (0 < x_i < n)\)。
每个时刻有且仅有一只老鼠可以向右移动一位,猫也会向右移动一位。如果猫的位置和一只老鼠重合,猫就会吃掉这只老鼠,已经在洞的位置上的老鼠不会被吃掉。
求最多有多少只老鼠可以不被猫吃掉。
思路
这道题的解法是贪心。
现将所有老鼠按照坐标排序,再依次从第 \(n\) 个老鼠开始,从右到左依次尝试将每一个老鼠移动到洞里,如果当前的老鼠已经被吃掉了就停止(所有老鼠已经不是到了洞里就是被吃掉)。
如果不移动最右侧的老鼠而是移动其他老鼠,最右侧老鼠不动而猫向右移动,猫与所有老鼠构成的区间长度缩短,答案显然不会更优。
代码
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 400000 + 5;
int a[MAXN];
int n, k;
int main() {
int T;
cin >> T;
while(T--) {
cin >> n >> k;
for(int i = 1; i <= k; i++) {
cin >> a[i];
}
sort(a + 1, a + k + 1);
int cat = 0, ans = 0;
for(int i = k; i >= 1; i--) {
if(cat >= a[i]) {
break;
}
int dis = n - a[i];
ans++;
cat += dis;
}
cout << ans << endl;
}
return 0;
}
CF1593D1 All are Same
题意
输入 \(n\) 个数 \(a_1,a_2,...a_n\),每次操作可以将一个数减小 \(k\),若干次操作后所有的数的值全部相同,求 \(k\) 的最大值。如果 \(k\) 可以任意大,输出 \(-1\)。
思路
将一个数 \(a\) 不断减去相同的数 \(k\) 之后,变为另一个数 \(b\) ,\(k\) 显然是 \(|b - a|\) 的约数,拓展到 \(n\) 个数后同样成立。
所以题目中所求的 \(k\) 就是 \(\gcd(a_1 - a_2, a_2 - a_3, a_3 - a_4,... a_{n - 1} - a_n)\),即对差分求最大公约数。
代码
#include<iostream>
#include<fstream>
#include<algorithm>
using namespace std;
const int MAXN = 40 + 5;
int a[MAXN];
int n;
int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
int main() {
int T;
cin >> T;
while(T--) {
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> a[i];
}
int ans = 0;
for(int i = 2; i <= n; i++) {
ans = gcd(ans, a[i] - a[i - 1]);
}
if(ans < 0) {
ans = -ans;
}
if(ans == 0) {
cout << -1 << endl;
} else {
cout << ans << endl;
}
}
return 0;
}
CF1593E Gardener and Tree
题意
对一棵 \(n\) 个节点的树进行 \(k\) 次操作,每次操作删去当前树的所有叶结点,求 \(k\) 次操作后树还剩下多少个节点。
思路
注意到每个节点“在哪一次操作中被删去”的属性有明显的先后顺序,所以我们可以对这棵树进行一个拓扑排序。
定义每个节点“在哪一次操作中被删去”的值为 \(rnk_i\)。每次检查到 \(deg_v = 1\) 的节点 \(v\) 就将其入队,同时用“引荐”它入队的节点 \(u\) 计算 \(v\) 的 \(rnk\) 值,\(rnk_v = rnk_u + 1\)。
最后检查哪些节点的 \(rnk\) 值小于 \(k\),这些节点会被剪掉,其他节点的数量就是答案。
代码
#include<iostream>
#include<fstream>
#include<algorithm>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
const int MAXN = 400000 + 5;
vector<int> G[MAXN];
int deg[MAXN], rnk[MAXN];
int n, k;
void toposort() {
queue<int> q;
for(int i = 1; i <= n; i++) {
if(deg[i] == 1) {
q.push(i);
rnk[i] = 1;
}
}
while(!q.empty()) {
int u = q.front(); q.pop();
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if(--deg[v] == 1) {
rnk[v] = rnk[u] + 1;
q.push(v);
}
}
}
}
int main() {
int T;
cin >> T;
while(T--) {
memset(deg, 0, sizeof(deg));
memset(rnk, 0, sizeof(rnk));
cin >> n >> k;
for(int i = 1; i <= n; i++) {
G[i].clear();
}
for(int i = 1; i <= n - 1; i++) {
int u, v;
cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
deg[u]++; deg[v]++;
}
toposort();
int ans = n;
for(int i = 1; i <= n; i++) {
if(rnk[i] <= k) {
ans--;
}
}
cout << ans << endl;
}
return 0;
}