A (简单模拟)-Elections
题意:
给出三个整数,每次对这个整数加1,问对于每一个整数,最少需要几次操作可以使得,他变成三个数中唯一的最大值.
思路:
对于不等于 max 的元素,最少操作次数为 max - x + 1.
对于等于max 的元素,如果有多个数字等于 max 的话,那么最少操作次数就是1,否则是0.
参考代码:
void solve() {
std::vector<int> a(3);
std::cin >> a[0] >> a[1] >> a[2];
int max = *max_element(a.begin(),a.end());
bool f1 = false, f2 = false;
for (int i = 0; i < 3; i++) {
if (a[i] == max) {
if (!f1) {
f1 = true;
} else {
f2 = true;
break;
}
}
}
for (int i = 0; i < 3; i++) {
if (a[i] == max) {
a[i] = f2;
} else {
a[i] = max - a[i] + 1;
}
}
for (int i = 0; i < 3; i++) {
std::cout << a[i] << " \n"[i == 2];
}
}
B (思维.BFS) -Make it Divisible by 25
题意:
给你一个数字,每一次可以删去任意一位数字,问最少需要多少次操作,使得这个数字是 25 的倍数?
思路:
因为 25 ∗ 4 = 100
所以,对于百位即以上的位数,无论我们取什么都可以整除
我们只需关注个位和十位
因此,每次删除要么删除个位上的数,要么删除十位上的数,这样一来枚举的情况就大大减少了
我们 bfs.
参考代码:
#include <bits/stdc++.h>
using pll = std::pair<ll, ll>;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::function<int(ll)> bfs = [&](ll num) {
std::queue<pll> que;
que.push({num, 0});
std::map<ll, bool> mp;
while (!que.empty()) {
pll p = que.front();
que.pop();
if (p.first < 25) {
continue;
}
if (p.first % 25 == 0) {
return p.second;
}
pll pp = {p.first / 10, p.second + 1};
pll ppp = {p.first / 100 * 10 + p.first % 10, p.second + 1};
mp[pp.first] = 1;
que.push(pp);
mp[ppp.first] = 1;
que.push(ppp);
}
};
int T;
std::cin >> T;
while (T--) {
ll num;
std::cin >> num;
std::cout << bfs(num) << "\n";
}
return 0;
}
C (贪心.模拟.前缀和.二分) -Save More Mice
思路:
贪心,让距离洞口近的老鼠先出发躲到洞中,如果猫的 pos < 老鼠的 pos,那么这一只老鼠可以进入洞中躲起来,否则,将被猫抓到.
参考代码:
while (t--) {
int n, k;
std::cin >> n >> k;
std::vector<int> a(k);
for (int i = 0; i < k; i++) {
std::cin >> a[i];
}
int pos = 0, ans = 0;
std::sort(a.begin(), a.end(), std::greater<int>());
for (int i = 0; i < k; i++) {
if (a[i] > pos) {
ans++;
pos += n - a[i];
} else {
break;
}
}
std::cout << ans << "\n";
}
while (t--) {
int n, k;
std::cin >> n >> k;
std::vector<int> a(k + 1);
for (int i = 1; i <= k; i++) {
std::cin >> a[i];
}
std::sort(a.begin() + 1, a.end(), std::greater<int>());
std::vector<ll> sum(k + 1);
for (int i = 1; i <= k; i++) {
sum[i] = sum[i-1] + (n - a[i]);
}
std::cout << std::lower_bound(sum.begin() + 1,sum.end(),n)-sum.begin() - 1 << '\n';
}
D1 (思维.数论)-All are Same
思路:
两个数 a,b,对这两个数执行操作
a减去 x 个k,b 减去 y 个k.
如此a - x*k = b − y*k.
那么 a %k == b %k.
a,b对 k 取余的余数一定要相同
那么(a − b) mod k = 0
k 一定为 abs(a - b)中的因数!
我们随意找两个数 a,b,枚举 abs(a - b)的因数一一验证即可
参考代码:
#include <bits/stdc++.h>
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int T;
std::cin >> T;
while (T--) {
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; i++) {
std::cin >> a[i];
}
std::function<bool(int)> check = [&](int num) {
for (int i = 1; i < n; i++) {
if ((a[i] % num + num) % num != (a[i - 1] % num + num) % num)
return false;
}
return true;
};
std::sort(a.begin(), a.end());
int big = a[n - 1] - a[0];
int ans = -1;
for (int i = 1; i * i <= big; i++) {
if (big % i == 0) {
if (i > ans && check(i)) {
ans = i;
}
if (big / i > ans && check(big / i)) {
ans = big / i;
}
}
}
std::cout << ans << "\n";
}
return 0;
}
D2 (思维.数论)- Half of Same
基本策略和 D1并没有什么不同
只是这里要求如果有至少一半的数字他们关于k同余即可
如此,我们可以枚举所有的数字对,
按照 D1 的策略找到所有的 k,能满足至少有一半的元素同余.
参考代码:
#include <bits/stdc++.h>
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int T;
std::cin >> T;
while (T--) {
int n;
std::cin >> n;
std::vector<int> a(n);
std::function<bool(int)> check = [&](int num)
{
std::map<int, int> mp;
for (int i = 0; i < n; i++) {
mp[(a[i] % num + num) % num]++;
}
for (auto p : mp) {
if (p.second >= n / 2) {
return true;
}
}
return false;
};
std::function<int(int)> solve = [&](int num)
{
int ans = 0;
for (int i = 1; i * i <= num; i++) {
if (num % i == 0) {
if (i > ans && check(i)) {
ans = i;
}
if (num / i > ans && check(num / i)) {
ans = num / i;
}
}
}
return ans;
};
for (int i = 0; i < n; i++) {
std::cin >> a[i];
}
std::sort(a.begin(), a.end());
std::map<int, int> mp;
for (int i = 0; i < n; i++) {
mp[a[i]]++;
}
int ans = 0;
for (auto p : mp) {
if (p.second >= n / 2) {
ans = -1;
break;
}
}
if (ans == -1) {
std::cout << ans << "\n";
continue;
}
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
ans = std::max(ans, solve(a[j] - a[i]));
}
}
std::cout << ans << "\n";
}
return 0;
}
E.(BFS) - Gardener and Tree
一个点可删除,当且仅当他的度数 ≤1
我们记录下所有的度数,从所有度数 ≤1 的点开始 bfs 即可
保证 bfs 的层数 ≤ k
答案便是 n − 所有走过的点数.
参考代码:
#include <bits/stdc++.h>
const int maxn = 4e5 + 100;
std::vector<int> G[maxn];
bool de[maxn];
int du[maxn];
int n, k;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int T;
std::cin >> T;
while (T--) {
std::cin >> n >> k;
for (int i = 1; i <= n; i++) {
G[i].clear(), du[i] = de[i] = 0;
}
for (int i = 1, u, v; i < n; i++) {
std::cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
du[u]++;
du[v]++;
}
std::queue<std::pair<int, int>> que;
for (int i = 1; i <= n; i++) {
if (du[i] <= 1) {
que.push({i, 1});
}
}
while (!que.empty()) {
std::pair<int, int> p = que.front();
que.pop();
if (de[p.first]) {
continue;
}
de[p.first] = 1;
if (p.second == k) {
continue;
}
for (int v : G[p.first]) {
du[v]--;
if (du[v] <= 1 && !de[v])
que.push({v, p.second + 1});
}
}
int ans = n;
for (int i = 1; i <= n; i++) {
if (de[i]) {
--ans;
}
}
std::cout << ans << "\n";
}
return 0;
}