【2024暑110】ACM暑期第五次测验(个人赛)题解
A - 快速幂
Solution
由于
首先,我们将找到
如果
Code
#include <bits/stdc++.h>
using namespace std;
int main(){
int a, b, c; cin >> a >> b >> c;
if (c % 2 == 0)
cout << (abs(a) < abs(b) ? "<" : abs(a) == abs(b) ? "=" : ">") << endl;
else
cout << (a > b ? ">" : a == b ? "=" : "<") << endl;
return 0;
}
B - 存钱
Solution
签到题,直接模拟即可
C - Imbalanced XiaoMo
Question
给出一个序列
Solution #1
我们想要最小化最大值,那么肯定需要把最大的间隙缩小,如果最大的间隙有两个,那么最大的间隙就是答案,否则能缩小最大间隙
思考怎样缩小最大间隙才能使得最大值最小,肯定是对半分最小的间隙,假设
这是一个经典问题,我们可以用二分或者双指针解决
Code #1
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int, int> pii;
const int INF = 1e18;
void solve() {
int n, m, k; cin >> n >> m >> k;
vector<int> a(n + 1), d(m + 1), f(k + 1, 0);
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= m; i++) cin >> d[i];
for (int i = 1; i <= k; i++) cin >> f[i];
pii mx1 = {-1,0}, mx2 = {-1,0};
for (int i = 1; i < n; i++) {
int x = a[i + 1] - a[i];
if (x > mx1.first) { mx2 = mx1; mx1 = {x, i}; }
else if (x > mx2.first) { mx2 = {x, i}; }
}
if (mx1.first == mx2.first) {
cout << mx1.first << '\n';
return ;
}
// 把 pos1 的位置拆开
int mid = (a[mx1.second] + a[mx1.second + 1]) / 2;
sort (d.begin() + 1, d.end());
sort (f.begin() + 1, f.end());
int ret = mx1.first;
for (int i = 1; i <= m; i++) {
auto check = [&](int pos) {
if (pos < 1 || pos > k) return INF;
int x = d[i] + f[pos];
if (!(x > a[mx1.second] && x < a[mx1.second + 1])) return INF;
return max (x - a[mx1.second], a[mx1.second + 1] - x);
};
int pos = lower_bound(f.begin() + 1, f.end(), mid - d[i]) - f.begin();
ret = min (ret, check(pos));
ret = min (ret, check(pos - 1));
ret = min (ret, check(pos + 1));
}
cout << max (mx2.first, ret) << '\n';
}
signed main() {
int t; cin >> t;
while (t--) solve();
}
Solution #2
“使得最大值最小”是一个经典的二分答案模型,我们计算出在一个题都不添加的情况下的不平衡性
问题就变成了能否通过添加一道题使得最终的不平衡性小于等于
如果对于这个
Code #2
#include <bits/stdc++.h>
#define N 110000
#define M 220000
#define K 220000
#define int long long
using namespace std;
int t, n, m, k, a[N], d[M], f[K];
bool judge(int x);
signed main() {
scanf("%lld", &t);
while (t--) {
scanf("%lld%lld%lld", &n, &m, &k);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
for (int i = 1; i <= m; i++) scanf("%d", &d[i]);
sort(d + 1, d + 1 + m);
for (int i = 1; i <= k; i++) scanf("%d", &f[i]);
sort(f + 1, f + 1 + k);
int s = 0;
for (int i = 2; i <= n; i++)
s = max(s, a[i] - a[i - 1]);
int l = 0, r = s + 1;
while (l + 1 < r) {
int mid = (l + r) / 2;
if (judge(mid) == false)
l = mid;
else
r = mid;
}
printf("%lld\n", r);
}
return 0;
}
bool judge(int x) {
int id = 0;
for (int i = 2; i <= n; i++) {
if (a[i] - a[i - 1] > x) {
if (id != 0)
return false;
else
id = i;
}
}
if (id == 0)
return true;
if (a[id] - a[id - 1] > 2 * x)
return false;
int mbl = a[id] - x, mbr = a[id - 1] + x;
bool flag = false;
for (int i = 1; i <= m; i++) {
int l = 0, r = k + 1;
while (l + 1 < r) {
int mid = (l + r) / 2;
if (d[i] + f[mid] < mbl)
l = mid;
else
r = mid;
}
if (l != k && d[i] + f[l + 1] <= mbr) {
flag = true;
break;
}
}
return flag;
}
D - dijikstra
Solution
由于边权都相同,考虑使用 bfs 得到最短路
我们在 bfs 时,需要记录下两个值:起点到
对于
Code
#include <bits/stdc++.h>
using namespace std;
constexpr int TT = 100003;
using pii = pair<int, int>;
int main() {
ios::sync_with_stdio(0);
int n, m; cin >> n >> m;
vector<vector<int>> g(n + 1);
for (int i = 0; i < m; i++) {
int a, b; cin >> a >> b;
g[a].push_back(b);
g[b].push_back(a);
}
vector<int> vis(n + 1, 0);
vector<pii> dis(n + 1, {0, 0});
queue<int> q;
vis[1] = 1; q.push(1); dis[1] = {0, 1};
while (!q.empty()) {
int u = q.front(); q.pop();
for (int v : g[u]) {
if (!vis[v]) {
vis[v] = 1;
auto [d, c] = dis[u];
auto &[d_, c_] = dis[v];
d_ = d + 1; c_ = c;
q.push(v);
}
else {
auto [d, c] = dis[u];
auto &[d_, c_] = dis[v];
if (d + 1 == d_) c_ = (c_ + c) % TT;
}
}
}
for (int i = 1; i <= n; i++)
cout << dis[i].second << '\n';
return 0;
}
E - 约数最大值
Solution
有点类似于 PTA 题,for 循环枚举