2025组队训练赛第 26 场
A. An Olympian Math Problem
打表发现应该输出 n - 1.
cpp
#include <iostream>
using namespace std;
int main() {
int t;
long long n;
scanf("%d", &t);
while (t--) {
scanf("%lld", &n);
printf("%lld\n", n - 1);
}
return 0;
}B. The writing on the wall
单调栈
C. GDY
大模拟,我的 2 能管住 2,卡了 2h😇。
cpp
#include <iostream>
#include <cstring>
using namespace std;
const int N = 210, M = 20010;
const int ne[] = {0, 2, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1};
int a[M], t[N][14], num[N];
void solve() {
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; ++i) scanf("%d", &a[i]);
int cur = 1, now_card = 0, ls_person = 1, cur_person = 1;
// init
for (int i = 1; i <= n; ++i) {
for (int j = 0; j < 5; ++j) {
if (cur <= m) {
t[i][a[cur++]]++;
num[i]++;
}
}
}
bool first = true;
while (true) {
if (ls_person == cur_person) {
if (first) first = false;
else {
for (int i = 0; i < n; ++i) {
if (cur <= m) {
t[(cur_person + i - 1) % n + 1][a[cur++]]++;
num[(cur_person + i - 1) % n + 1]++;
}
}
}
for (int i = 1; i <= 13; ++i) {
if (t[cur_person][(i + 1) % 13 + 1]) {
t[cur_person][(i + 1) % 13 + 1]--;
now_card = (i + 1) % 13 + 1;
num[cur_person]--;
// cout << cur_person << " CHU " << (i + 1) % 13 + 1 << endl;
break;
}
}
// cout << endl;
ls_person = cur_person;
}
else {
if (t[cur_person][ne[now_card]]) {
t[cur_person][ne[now_card]]--;
num[cur_person]--;
ls_person = cur_person;
now_card = ne[now_card];
// cout << cur_person << " CHU " << now_card << endl;
}
else if (now_card != 2 && t[cur_person][2]) {
t[cur_person][2]--;
num[cur_person]--;
ls_person = cur_person;
now_card = 2;
// cout << cur_person << " CHU " << now_card << endl;
}
}
if (num[cur_person] <= 0) break;
// for (int i = 1; i <= 13; ++i) cout << t[cur_person][i] << ' ';
// cout << endl;
cur_person = cur_person % n + 1;
}
for (int i = 1; i <= n; ++i) {
if (num[i] == 0) printf("Winner\n");
else {
int res = 0;
for (int j = 1; j <= 13; ++j) {
res += t[i][j] * j;
t[i][j] = 0;
}
num[i] = 0;
printf("%d\n", res);
}
}
}
int main() {
int T;
scanf("%d", &T);
for (int i = 1; i <= T; ++i) {
printf("Case #%d:\n", i);
solve();
}
return 0;
}E. AC Challenge
状压 dp,维护第 i 次选后结果是一个 bitmask 的得分最大值。
我状态转移神秘不取 max,挂掉了一次。
cpp
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
typedef long long LL;
const int N = 20;
LL f[1 << N], g[1 << N];
LL a[N], b[N];
int v[N];
int main() {
int n;
scanf("%d", &n);
for (int i = 0; i < n; ++i) {
int t;
scanf("%lld%lld%d", &a[i], &b[i], &t);
for (int j = 0; j < t; ++j) {
int tmp;
scanf("%d", &tmp);
v[i] |= 1 << (tmp - 1);
}
}
memset(f, -0x3f, sizeof(f));
memset(g, -0x3f, sizeof(g));
LL inf = f[0], res = 0;
f[0] = 0;
int tmp = 0;
for (int i = 1; i <= n; ++i) {
for (int msk = 0; msk < (1 << n); ++msk) {
if (f[msk] == inf) continue;
for (int j = 0; j < n; ++j) {
if ((msk >> j & 1) || ((v[j] & msk) != v[j])) continue;
else {
g[msk | (1 << j)] = max(g[msk | (1 << j)], f[msk] + a[j] * i + b[j]);
res = max(res, g[msk | (1 << j)]);
}
}
}
tmp |= 1 << (i - 1);
swap(f, g);
memset(g, -0x3f, sizeof(g));
}
printf("%lld\n", res);
return 0;
}G. Lpl and Energy-saving Lamps
似乎是个平衡树,用 set 能做。
I. Skr
裸的回文自动机板子。
J. Nanjing Sum
对于一个数做质因数分解,如果最高幂次超过 2,必定有一边不是 square-free integer,所有的分解方案是把幂次为 2 的一边取一个,其余的任意放。
利用线筛的过程 dp,考虑标记的过程 v[i * prime[j]] = prime[j],检查 i 中是否出现过这个约数 prime[j] 以及出现是否已经两次,更新答案。
cpp
#include <iostream>
using namespace std;
const int N = 20000010;
int v[N], prime[N], l;
long long f[N];
void init() {
int n = 20000000;
f[1] = 1;
for (int i = 2; i <= n; ++i) {
if (v[i] == 0) {
v[i] = i;
prime[++l] = i;
f[i] = 2;
}
for (int j = 1; j <= l; ++j) {
if (prime[j] > v[i] || prime[j] > n / i) break;
v[i * prime[j]] = prime[j];
if (v[i] != prime[j]) {
f[i * prime[j]] = f[i] * 2;
}
else if (v[i] == prime[j] && v[i / v[i]] != prime[j]) {
f[i * prime[j]] = f[i] / 2;
}
else {
f[i * prime[j]] = 0;
}
}
}
for (int i = 1; i <= n; ++i) {
f[i] += f[i - 1];
}
}
int main() {
init();
int T;
scanf("%d", &T);
while (T--) {
int n;
scanf("%d", &n);
printf("%lld\n", f[n]);
}
return 0;
}L. Magical Girl Haze
裸的分层图最短路板子。