2025春训第十六场

7 min read
差点就 ak 了,有点可惜,感谢学姐手下留情😭。
A. Number Maximization
签到题 * 1
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
string s;
cin >> s;
sort(s.begin(), s.end(), greater<char>());
cout << s << endl;
return 0;
}
B. Simplified Calendar System
签到题 * 2
#include <iostream>
using namespace std;
int main() {
int a, b, c, d, e, f, g;
cin >> a >> b >> c >> d >> e >> f >> g;
cout << (d - 1 + (e - a) + (f - b) * 30 + (g - c) * 360) % 7 + 1 << endl;
return 0;
}
C. Letter Frequency
签到题 * 3
#include <iostream>
#include <map>
using namespace std;
string s[30];
int main() {
int n, len = 0;
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> s[i];
len = max(len, (int)s[i].length());
}
for (int i = 1; i <= len; ++i) {
cout << i << ":";
map<char, int> mp;
for (int j = 1; j <= n; ++j) {
if (s[j].length() >= i) mp[s[j][i - 1]]++;
}
int mx = 0;
for (auto [a, b] : mp) mx = max(mx, b);
for (auto [a, b] : mp) if (b == mx) cout << ' ' << a;
cout << endl;
}
return 0;
}
D. Pseudo Pseudo Random Numbers
数据非常的小,所以直接暴力枚举检查就行,签到题 * 4
#include <iostream>
using namespace std;
int n, k;
bool check(int mask) {
int ls = -1, len = 0;
for (int i = 0; i < n; ++i) {
if ((mask >> i & 1) != ls) len = 1;
else len++;
ls = mask >> i & 1;
if (len > k) return false;
}
return true;
}
int main() {
int t = 0;
cin >> n >> k;
for (int i = 0; i < (1 << n); ++i) {
if (check(i)) t++;
}
cout << t << endl;
return 0;
}
E. Word Tree
没什么特别的,就是最小生成树。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
string s[1010];
int fa[1010];
vector<pair<int, pair<int, int>>> ed;
int dis(string a, string b) {
int n = a.length();
int d = 0;
for (int i = 0; i < n; ++i) {
d += abs(a[i] - b[i]);
}
return d;
}
int getfa(int x) {
return x == fa[x] ? x : fa[x] = getfa(fa[x]);
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int n, l;
cin >> n >> l;
for (int i = 1; i <= n; ++i) {
cin >> s[i];
fa[i] = i;
for (int j = 1; j < i; ++j) {
ed.push_back({dis(s[i], s[j]), {i, j}});
}
}
int res = 0;
sort(ed.begin(), ed.end());
for (auto [w, p] : ed) {
int x = getfa(p.first), y = getfa(p.second);
if (x == y) continue;
else {
fa[y] = x;
res = max(res, w);
}
}
cout << res << endl;
return 0;
}
F. House Prices Going Up
树状数组(线段树)模板题。
#include <iostream>
using namespace std;
const int N = 500010;
long long tr[N];
int n;
void add(int u, int v) {
for (; u <= n; u += u & -u) {
tr[u] += v;
}
}
long long query(int u) {
long long res = 0;
for (; u; u -= u & -u) {
res += tr[u];
}
return res;
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
int t;
scanf("%d", &t);
add(i, t);
}
int q;
scanf("%d", &q);
while (q--) {
char s[2];
int x, y;
scanf("%s%d%d", s, &x, &y);
if (s[0] == 'U') add(x, y);
else printf("%lld\n", query(y) - query(x - 1));
}
return 0;
}
G. Which Number
到这里难度开始正常了,这道题是二分答案+容斥原理,先二分答案,然后用容斥原理检查前面合法的数的个数。
我不慎 WA 了一次好像是爆 long long 了。
#include <iostream>
using namespace std;
long long a[20], k;
long long n;
bool check(long long mid) {
__int128_t cnt = 0;
for (int mask = 0; mask < (1 << k); ++mask) {
__int128_t t = 1;
int op = 0;
for (int j = 0; j < k; ++j) {
if (mask >> j & 1) {
op++;
t *= a[j];
}
}
op = (op & 1) ? -1 : 1;
cnt += (mid / t) * op;
}
return cnt >= n;
}
int main() {
scanf("%lld%d", &n, &k);
for (int i = 0; i < k; ++i) {
scanf("%lld", &a[i]);
}
__int128_t l = 1, r = __LONG_LONG_MAX__;
while (l < r) {
long long mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
printf("%lld\n", (long long)l);
return 0;
}
I. Share Auction
又是一道二分题,考虑这样一个问题,对于一个 lot 如果一块一块的 bid 每一块的收益都会逐渐减小,目标状态是使得最后 bid 了 v 之后目标状态是一个相对均匀的状态。具体来说是让其中的一部分(有可能是全部)在投了 v 之后再投 1 时或者的收益在误差允许的范围内尽可能相等,这样就能最大程度保证每次投的都是最优解。
于是可以二分最终投一块钱的收益,然后计算想把收益压到 ≤ mid 的时候需要 bid 多少,和 v 比较,找到一个尽可能接近 v 的(可以稍微大一点,因为有的情况最后好几个都相等,一降低每个都得 bid 1,无法到 v,但是不影响最后计算,因为都一样,最后投哪个都行)。找到之后按二分的 check 函数的逻辑再跑一次,这一次要加上最大限制 v,跑的过程中记录收益累加即可。
#include <iostream>
#include <queue>
using namespace std;
const int N = 100010;
struct Node {
double rate;
int tot_val;
int voted = 0, other_vote;
bool operator <(const Node &_) const {
return rate < _.rate;
}
double vote(int t) {
double r = (double)voted / (voted + other_vote) * tot_val;
voted += t;
rate = (double)(voted + 1) / (voted + other_vote + 1) * tot_val - (double)voted / (voted + other_vote) * tot_val;
return (double)voted / (voted + other_vote) * tot_val - r;
}
} a[N];
int n, v;
long long check(double val) {
long long res = 0;
for (int i = 1; i <= n; ++i) {
int l = 0, r = 100000000;
while (l < r) {
int mid = l + r >> 1;
auto bk = a[i];
bk.vote(mid);
if (bk.rate < val) r = mid;
else l = mid + 1;
}
res += l;
}
return res;
}
int main() {
double L = 0, R = 0;
scanf("%d%d", &n, &v);
for (int i = 1; i <= n; ++i) {
scanf("%d%d", &a[i].tot_val, &a[i].other_vote);
a[i].vote(0);
R = max(R, a[i].rate);
}
while (R - L > 1e-9) {
double mid = (L + R) / 2;
if (check(mid) >= v) L = mid;
else R = mid;
}
double res = 0;
for (int i = 1; i <= n; ++i) {
int l = 0, r = v;
while (l < r) {
int mid = l + r >> 1;
auto bk = a[i];
bk.vote(mid);
if (bk.rate < L) r = mid;
else l = mid + 1;
}
res += a[i].vote(l);
v -= l;
}
if (v) return 123;
else printf("%f\n", res);
return 0;
}
J. Desert Travel
基本功大考核,最小生成树 + 树上倍增,思维难度不是很大,但是比较有操作难度,这中间炸了死哪都不知道。
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 5010;
struct Edge {
int x, y;
double w;
} a[N * (N - 1) / 2];
int x[N], y[N];
int fa[N];
int f[N][15], dep[N];
double g[N][15];
vector<pair<double, int>> ed[N];
int getfa(int x) {
return x == fa[x] ? x : fa[x] = getfa(fa[x]);
}
void dfs(int x) {
for (int i = 1; i < 15; ++i) {
f[x][i] = f[f[x][i - 1]][i - 1];
g[x][i] = max(g[x][i - 1], g[f[x][i - 1]][i - 1]);
}
for (auto [w, y] : ed[x]) {
if (y == f[x][0]) continue;
g[y][0] = w;
f[y][0] = x;
dep[y] = dep[x] + 1;
dfs(y);
}
}
int main() {
int n, m = 0;
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
fa[i] = i;
scanf("%d%d", &x[i], &y[i]);
for (int j = 1; j < i; ++j) {
a[++m] = {j, i, sqrt(pow(x[i] - x[j], 2) + pow(y[i] - y[j], 2))};
}
}
sort(a + 1, a + m + 1, [](Edge a, Edge b) {
return a.w < b.w;
});
for (int i = 1; i <= m; ++i) {
int x = getfa(a[i].x), y = getfa(a[i].y);
if (x == y) continue;
fa[y] = x;
ed[a[i].x].push_back({a[i].w, a[i].y});
ed[a[i].y].push_back({a[i].w, a[i].x});
}
dep[1] = 1;
dfs(1);
int q;
scanf("%d", &q);
while (q--) {
int x, y;
double res = 0;
scanf("%d%d", &x, &y);
if (dep[x] < dep[y]) swap(x, y);
for (int i = 14; i >= 0; --i) {
if (dep[f[x][i]] >= dep[y]) {
res = max(res, g[x][i]);
x = f[x][i];
}
}
if (x != y) {
for (int i = 14; i >= 0; --i) {
if (f[x][i] != f[y][i]) {
res = max(res, max(g[x][i], g[y][i]));
x = f[x][i], y = f[y][i];
}
}
res = max(res, max(g[x][0], g[y][0]));
}
printf("%f\n", res);
}
return 0;
}
0
Subscribe to my newsletter
Read articles from Star directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Star
Star
A Chinese OIer and a tosser.