2026夏个人训练赛第三十三场
A. 前缀串
cpp
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
string s;
int n;
cin >> s >> n;
string res;
for (int i = 1; i <= n; ++i) {
string t;
cin >> t;
if (t.length() >= s.length() && t.substr(0, s.length()) == s) {
if (res.empty()) res = t;
else res = min(res, t);
}
}
cout << res << '\n';
return 0;
}B. 放椅子
cpp
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
long long res = 0;
int n;
cin >> n;
vector<int> a(n), b(n);
for (int i = 0; i < n; ++i) {
cin >> a[i] >> b[i];
}
sort(a.begin(), a.end()), sort(b.begin(), b.end());
for (int i = 0; i < n; ++i) res += max(a[i], b[i]);
cout << res + n << '\n';
return 0;
}C. 天天爱消除
cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 310;
int f[N][N], col[N];
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int n, a, b, c;
cin >> n >> a >> b >> c;
for (int i = 1; i <= n; ++i) cin >> col[i];
for (int i = 1; i <= n; ++i) f[i][i] = a;
for (int len = 2; len <= n; ++len) {
for (int l = 1; l <= n - len + 1; ++l) {
int r = l + len - 1;
for (int k = l; k < r; ++k) f[l][r] = max(f[l][r], f[l][k] + f[k + 1][r]);
if (col[l] == col[r]) {
f[l][r] = max(f[l][r], f[l + 1][r - 1] + b);
for (int k = l + 1; k < r; ++k) {
if (col[k] == col[l])
f[l][r] = max(f[l][r], f[l + 1][k - 1] + f[k + 1][r - 1] + c);
}
}
}
}
cout << f[1][n] << '\n';
return 0;
}D. 四元组计
枚举中间两个,然后维护前缀计数和后缀的计数统计答案。
cpp
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 5010;
int pre[N][N], suf[N][N], a[N];
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int n;
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
pre[i][a[i]] = suf[i][a[i]] = 1;
for (int j = 1; j <= n; ++j) pre[i][j] += pre[i - 1][j];
}
for (int i = n; i; --i) {
for (int j = 1; j <= n; ++j) {
suf[i][j] += suf[i + 1][j];
}
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
pre[i][j] += pre[i][j - 1];
suf[i][j] += suf[i][j - 1];
}
}
LL res = 0;
for (int i = 2; i < n - 1; ++i) {
for (int j = i + 1; j < n; ++j) {
if (a[i] > a[j]) {
res += (LL)(pre[i - 1][a[j]] * (suf[j + 1][n] - suf[j + 1][a[i]]));
}
}
}
cout << res << '\n';
return 0;
}E. 年会小游戏
最优解的质因数很少,而且是连续的一段最小的,dfs 加剪枝会跑的非常快。
cpp
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int p[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53};
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T;
cin >> T;
while (T--) {
LL n, res = 0, cnt = 0;
cin >> n;
int c[16]{};
auto dfs = [&](auto && self, int x, int pre, __int128_t cur, LL prod) {
if (cur > res && prod < cnt) return;
else if (cur * 2 > n || x == 16) {
if (prod > cnt || prod == cnt && cur < res) res = cur, cnt = prod;
return;
}
else {
int t = 0;
do {
self(self, x + 1, t, cur, prod * (t + 1));
t++;
cur *= p[x];
} while (t <= pre && cur <= n);
}
};
dfs(dfs, 0, 60, 1, 1);
cout << res << ' ' << cnt << '\n';
}
return 0;
}F. 公司搬迁
几乎是 2-SAT 板子题了,每个人有 A 和 B 两个状态二选一
- 只要能找到对应的人就是要么都在要么都不在,两个人的 A 之间、两个人的 B 之间分别连边
- 其中一个找不到说明这个人只能选另一个,给另一个连单向边
然后跑 tarjan 看一下是否矛盾。
cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int head[N * 2], ne[N * 4], ver[N * 4], tot;
int dfn[N * 2], low[N * 2], st[N * 2], ins[N * 2], id[N * 2], tp, t, scc_cnt;
unordered_map<int, int> mp;
int p[N];
void add(int x, int y) {
ver[++tot] = y, ne[tot] = head[x], head[x] = tot;
}
void tarjan(int x) {
dfn[x] = low[x] = ++t;
st[++tp] = x;
ins[x] = 1;
for (int i = head[x]; i; i = ne[i]) {
int y = ver[i];
if (!dfn[y]) {
tarjan(y);
low[x] = min(low[x], low[y]);
}
else if (ins[y]) low[x] = min(low[x], dfn[y]);
}
if (dfn[x] == low[x]) {
int y;
++scc_cnt;
do {
y = st[tp--];
id[y] = scc_cnt;
ins[y] = 0;
} while (y != x);
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T;
cin >> T;
while (T--) {
int n, a, b;
cin >> n >> a >> b;
tot = 0;
fill(head, head + n * 2 + 1, 0);
fill(dfn, dfn + n * 2 + 1, 0);
mp.clear();
for (int i = 1; i <= n; ++i) cin >> p[i], mp[p[i]] = i;
auto get = [&](int idx, int ch) {
return idx + ch * n;
};
for (int i = 1; i <= n; ++i) {
if (mp.find(a - p[i]) == mp.end()) add(get(i, 0), get(i, 1));
else add(get(i, 0), get(mp[a - p[i]], 0)), add(get(i, 1), get(mp[a - p[i]], 1));
if (mp.find(b - p[i]) == mp.end()) add(get(i, 1), get(i, 0));
else add(get(i, 1), get(mp[b - p[i]], 1)), add(get(i, 0), get(mp[b - p[i]], 0));
}
for (int i = 1; i <= n * 2; ++i) {
if (!dfn[i]) tarjan(i);
}
bool f = true;
for (int i = 1; i <= n; ++i) {
if (id[i] == id[i + n]) {
f = false;
break;
}
}
cout << (f ? "YES\n" : "NO\n");
}
return 0;
}其他没做的题
- 走亲戚
- K-ary Heap
- Is Today Friday?
- Train Driver
- Can They Go to Galar?
- Upgrading Technology