CSP-S 2025 挂分记
ElectricArc · · 生活·游记
いいな いいなと 欲しがってたのに
夢は遠くて 現実ばっかで :::align{right} 嘴上说着真好啊 真好啊 分明是如此渴望
可梦想触不可及 现实依旧如此 :::
好耀眼。
省流:预估
啊,这绝望的轮回!让我想到了去年,第一轮一等奖,第二轮二等奖,NOIP 三等奖。难道今年也要重蹈覆辙吗?
停课三天。
Day -2
上午打神秘模拟赛,好敷衍的题面和大样例。
获得了
下午看题解补题。补了两题就不想补了。
回宿舍跟舍友聊了一晚上现状,竞赛还是太难了。
Day -1
上午是我组织的模拟赛,写模拟赛的题解。
下午讲题。哦草,我怎么不会 dp?
晚上被教练拉去机构打模拟赛。哦草,垃圾样例,全过了也只有 45 pts。后面的全都不会。喜提 70 pts。
回宿舍,听同学说语文老师搞了默写小测,50 个空,错 3 个要重新默写。哦草。
Day 0
补题,写题解,什么都没有复习。
讲了下注意事项,又听了他人讲的注意事项。
Day 1 上午
看了航模表演,还是什么都没有复习。
坐校车出发,好困。
Day 1 下午
又回到了考 NOIP 2024 的考场,有点怀念啊。
压缩包密码(貌似)是 Ren5Jie4Di4Ling5%,人皆第零……?我不理解。赛后才知道是人皆爆零。
提前 3 分钟开始比赛。
先找监考要了 3 张草稿纸,怎么有监考整个了大波浪呢,还是个男的。
花了 40 分钟阅读所有题面并试图简化题意,怎么都有点抽象啊。
好吧,来看看 T1,手玩了一下样例,又看了眼特殊性质。觉得
/*
15:13
若无 > n/2,皆大欢喜。
最多只有一个部门会 > n/2,考虑让他跳槽。
否则,设立优先队列,
找到变化量(前 - 后)最小的(且未满, never exists)的那个部门跳槽。
做一次即可,因为不会再出现 > n/2 的情况了。
15:34 end!!!!!
*/
真好。看看 T2,写了个 Kruskal 板子放着。以为乡村和城市是同一个点,硬控了一小下。
放着,看 T3,写了个无法描述复杂度的暴力,期望 10 pts。
T4 写了个
再看回 T2,冲特殊性质 A,哦草,为什么输出的比答案要小啊。
只剩下两分钟,还是没有调出来,投降喵。只好整理文件,准备结束。
Day 1 晚上
:::info[教练在路上发现的神秘小卡片]
:::
原来 T4 的 A 性质这么好骗吗,哦草。好像并没有那么好骗。
跟教练和其他同学去外面吃饭。回到家已经十点多了。
Day inf
赛后突然回忆起 T2,当时大概是这么写的。
直接看源代码吧。
:::error[请你在 0.1 s 内找到错误]
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
const int N = 1e4 + 15, M = 1e6 + 7, MM = 2e6 + 7, K = 12;
const ll INF = 2e18;
int c[K], a[K][N];
// int freeCity[K];
struct Edge {
int u, v, w;
};
bool cmp (Edge A, Edge B) {
if (A.w == B.w) {
if (A.u == B.u) return A.v < B.v;
return A.u < B.u;
}
return A.w < B.w;
}
Edge given_edges[M], cur_edges[MM];
struct unionSet {
int fa[N];
int findfa(int u) {
return (fa[u] == u) ? (u) : (fa[u] = findfa(fa[u]));
}
void reset(int n) {
for (int i = 1; i <= n; i++) {
fa[i] = i;
}
}
} uset;
ll kruskal(int n, int cur_m) {
uset.reset(n);
sort(cur_edges + 1, cur_edges + cur_m + 1, cmp);
ll costs = 0;
int cnt = 0;
for (int i = 1; i <= cur_m; i++) {
if (cnt == n - 1) break; // is a tree
auto [u, v, w] = cur_edges[i];
if (u != v && uset.findfa(u) != uset.findfa(v)) {
costs += w;
uset.fa[u] = v;
cnt++;
}
}
return costs;
}
void sub1to4(int n, int m) {
for (int i = 1; i <= m; i++) {
cur_edges[i] = given_edges[i];
}
ll res = kruskal(n, m);
printf("%lld\n", res);
return;
}
void subA(int n, int m, int k) {
// puts("A");
int cur_m = m;
for (int i = 1; i <= m; i++) {
cur_edges[i] = given_edges[i];
}
for (int i = 1; i <= k; i++) {
int freeCity = -1;
for (int j = 1; j <= n; j++) {
if (a[i][j] == 0) {
freeCity = j;
break;
}
}
for (int j = 1; j <= n; j++) {
if (j == freeCity) continue;
cur_m++;
cur_edges[cur_m] = {freeCity, j, a[i][j]};
}
}
ll res = kruskal(n, cur_m);
printf("%lld\n", res);
return;
}
int main() {
freopen("road.in", "r", stdin);
freopen("road.out", "w", stdout);
int n, m, k;
bool is_A = true;
scanf("%d %d %d", &n, &m, &k);
for (int i = 1; i <= m; i++) {
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
given_edges[i] = {u, v, w};
}
for (int i = 1; i <= k; i++) {
scanf("%d", &c[i]);
if (c[i] != 0) is_A = false;
for (int j = 1; j <= n; j++) {
scanf("%d", &a[i][j]);
}
}
// puts("A");
// printf("%d\n", is_A);
if (k == 0) {
sub1to4(n, m);
return 0;
}
if (is_A) {
subA(n, m, k);
return 0;
}
ll min_costs = INF;
for (int subset = 0; subset < (1 << k); subset++) {
ll cur_costs = 0;
int cur_m = m;
int towns = 0;
for (int i = 1; i <= m; i++) {
cur_edges[i] = given_edges[i];
// printf("%d: link(%d, %d, %d)\n", i, u, v, w);
}
for (int j = 0; j < k; j++) {
if (subset & (1 << j)) {
// select "TOWN" (j+1) to upgrade
int idx = j + 1;
for (int i = 1; i <= n; i++) {
cur_m++;
cur_edges[cur_m] = {n + towns + 1, i, a[idx][i]};
// printf("%d: link(%d, %d, %d)\n", cur_m, n + towns + 1, i, a[idx][i]);
}
towns++;
cur_costs += c[idx];
// printf("+= %d\n", c[idx]);
}
}
cur_costs += kruskal(n + towns, cur_m);
// printf("cur_cost = %lld\n", cur_costs);
min_costs = min(min_costs, cur_costs);
}
printf("%lld\n", min_costs);
return 0;
}
/*
15:40 start
16:36 16pts..?!
18:25 speA cannot do it
*/
:::
不 vp 模板赛导致的。哦草。
把那一行修改了一次重测,56 pts,哦草。
:::success[你真找不到错误?]
你在合并什么?!不合并根节点导致的。
:::
没想到 T4 CE 了,我的 8 pts 也打水漂了。
总结
最像 NOIP 的一次 CSP-S,也算是为真正的 NOIP 积累赛时经验吧。最后一次了。
- 赛前最后一天一定要睡足,不然会像我一样到了考点想睡觉。
- 赛前一定要复习模板,即便可能一个都涉及不到。
点名诋毁最小生成树的同辈,克露丝卡尔酱可爱! - 数据结构可以封装成结构体,便于日后调试。
- 前期读题的时间适当缩短至 30 分钟为宜。
- 涌现了 inf 个思路,不如先记下来。
- 实现好一个算法(模板、数据结构)就去自行造小样例检测,包括但不限于正确性和边界情况。不要一直相信你的眼力和直觉。
- 大样例非常难调,不如造符合特殊性质的小样例。
- 需要培养神秘的洞察力和积累常见的 trick,比如 T2 可以忽略原图最小生成树之外的边之类的。
- 在虚拟机编译的时候一定要看完所有的 error 和 warning,不要以为自己代码写得很对,然后就不想看 inf 个 warning,结果没看到 error 而爆零。
- 这里放个 OIer 常见错误,自己看去吧。
我必须说出来,这最后的台词……