本文同步发表在洛谷专栏,你也可以点击这里以获得更佳的阅读体验。下面是往期的迷惑行为大赏:
喜报,今年已经是内蒙古(NM)连续第三年举办 CSP-J/S 第二轮认证了!本次认证中,共有 $543$ 位选手参加了 CSP-J,有 $431$ 位选手参加了 CSP-S。今年的参赛人数变化十分耐人寻味,CSP-S 的参赛人数一如既往地疯狂增长,涨幅达到了 $59 \%$,但CSP-J 的参赛人数竟然有所减少,较去年降低了 $18 \%$,笔者推测这种现象或许与今年禁止低龄选手参赛的政策有关。
今年也是 CCF 第一次禁止低龄选手参赛,在这样的政策下,内蒙古的选手们在本次认证中的抱铃比例降低到了惊人的 $43 \%$,也就是说,有超过 $57 \%$ 的选手取得了不低于 $1$ 分的好成绩!这样的飞速进步无时无刻不在昭示着世人:内蒙古的 OI 事业正在蒸蒸日上!
这无疑证明了在世界经济下行的大背景下,我国民间仍然存在大量的慈善家,愿意为伟大的慈善事业贡献一份属于自己的力量。很遗憾的是,我们已经无法在今年的赛场上见到他们了,让我们期待他们长大后继续作出的伟大贡献吧!
笔者在撰写本文时,尚未得到 CCF 作出的有关选手准考证号与姓名、身份证号、手机号、洛谷账号等传统个人信息的相关性论证的调研报告。因此,我们将在下文中直接使用选手的准考证号,作为识别他们的唯一标识。
另一个原因是笔者目前暂时未掌握盒武器的相关核心技术。但笔者相信,随着科学技术的研究进一步深入,我们对相关技术的掌握会变得越来越深刻!
此外,在 AI 技术正在迅猛发展的当下,内蒙古的选手们也选择了紧跟时代的脚步,尝试以极具创新意义的方式拓宽“人机边界”的可能性,在算法竞赛的舞台上展开了一场极具前瞻性的实验性探索,新颖的研究结果实属令人叹为观止!我们将在下文中进一步讲述。
来自内蒙古的 $974$ 位选手中,在三个半(或四个(或七个半))小时的时间内,在 $3446$ 份扩展名为 .cpp(包括 .cpp.cpp)的文件(或文件夹)下,写下了:
- $6147$ 个
freopen(包括 $119$ 个//freopen或// freopen)。 - $4737$ 个
return。 - $3743$ 个
include(包括 $4$ 个includes)。 - $3734$ 个
stdin(和 $3$ 个sdtin)。 - $3689$ 个
stdout(和 $1$ 个stfout)(虽然笔者并不清楚为什么与。stdin的数量不相同) - $3333$ 个
main(和 $6$ 个mian)。 - $2973$ 个
bits/stdc++.h。 - $1240$ 个
fclose(虽然笔者并不理解为什么有这么多人写这个)。 - $346$ 个
iostream。 - $136$ 个
cstdio。 - $168$ 个
define。
除此之外,一个令人哀叹的事实是,在本次认证的代码中,笔者还发现了 $7$ 个 fuck、$4$ 个 cnm 和 $3$ 个 tmd,这是否成为暴戾语言势力重新入侵 OI 的表现,我们不得而知。但不得不承认的是,CCF 曾发表的《关于个别选手在NOIP 2021中使用暴戾语言的处罚公告》的含金量仍在上升。
但冰冷的数据总是无趣的,或许只有认真鉴赏过各位选手的代码后,我们才能领略其中的精髓。
NM-J00012 同学在他的每份代码末尾都编写了一段注释,似乎在传达着美好的期许。让我们恭喜这位同学在民间数据的测试中取得了 $163$ 分的好成绩!

NM-J00014 同学在 polygon 文件夹下创建了一份名为 palygon.cpp 的文件,并尝试读取和写入 palygon.in 和 palygon.out 文件。同时,我们有理由怀疑这位同学赛时所使用的键盘的拥有着 $\texttt{F}$ 在 $\texttt{D}$ 左侧的奇妙布局。

NM-J00021 同学在选手文件夹下创建了名为 number.cpp 的文件夹,并在 Untitled1 文件中写下了一份疑似受到宇宙射线影响的文字。

同理,家长也会用付费对宇宙射线表示支持。

NM-J00023 同学试图使用语言的力量感化评测姬。


为了防止无法清晰地辨识代码的语言,NM-J00028 同学贴心地向评测姬反复重申了这一要点。哪怕是在我国最北方的内蒙古,这份温暖也足以让内蒙古的冬天变得不再寒冷!

为了可以顺畅地使用 sort 函数,NM-J00044 同学在 polydon.cpp 中引入了 sort 头文件,并使用 frepone 函数完成了文件读写操作!

NM-J00052 在注释中写下了一串疑似祈愿的语句。但我们仍然要重申,盲目迷信是不可取的。

NM-J00087 同学疑似来自鄂尔多斯市东胜区第八小学,短短的一行注释,洋溢着的全部都是发自肺腑的自豪之情。这也无时无刻不在印证着一个事实:内蒙古的选手们太强大了!

NM-J00127 同学似乎不太喜欢循规蹈矩的标准(Standard),于是他在四份代码中都引入了 bit/c++.h。回想当下,似乎我们应该为这样敢于打破常规的勇气点赞。

NM-J00135 同学似乎正在尝试对文件读取和写入数据。

NM-J00144 同学在注释中写下了他对题意描述的不满,显然,$\sum$ 符号的含义似乎仍然不够深入人心。或许 CCF 在出题时也应考虑这一重要观点:普及组一定要普及。

值得一提的是,根据某知名算法竞赛平台对于同水平比赛的投题要求:
所有题出现的所有数学概念不得超过初中范围。(例如,求和不得使用 $\sum$ 符号,而应使用省略号表示。)
我们有理由怀疑出题人将已经被该平台驳回的题目投到了 CCF,并获得了通过。
时隔一年,NM-J00213 同学似乎仍然无法忘记令他心心念念的 CSP-J 2024,并在代码里尝试对 poker.in 和 poker.out 进行操作。

“数组开小了”往往是很多选手挂分的重要原因,因此 NM-J00216 同学针对这一隐患做了万全准备。

NM-J00260 同学同样表达了他对题目的不满,似乎本场比赛的题目被诟病并非个例。




NM-J00285 同学在注释中写下了一句刻骨铭心的感慨:十年 CSP 一场空,忘了代码见祖宗。

NM-J00290 同学显然是一位英语大手子,在比赛时也十分注重动词第三人称单数形式的运用。这也说明,哪怕是在 Scratch 横行的当下,英语水平仍然是踏入程序设计这一领域的巨大门槛。

尽管本场比赛的题目十分困难,但 NM-J00301 同学仍然保持了十分的热忱。在这样的热情下,想必他的 OI 生涯也一定会取得满意的成绩!

NM-J00322 为我们破解了收费网站,让我们感谢他的伟大贡献!终于看到好活了。

NM-J00398 同学也同样在选手文件夹中反复声明了所使用的语言,但目前笔者暂不了解这位同学和 NM-J00028 同学之间的关系。

NM-J00522 同学在注释中向一位可能名为 WLT 的同学传达了爱意,让我们向两位表达诚挚的祝福!

NM-J00537 同学在极度沉重的心情中,带着不甘的梦,以坚定的信念写下了一句振聋发聩的 //freopen。

NM-S00013 同学在他的代码中留下了一段简短的游记。

可以看出,NM-S00041 同学是真的不会了。不过,现在有人看到了(笑)。

NM-S00075 同学向世界打了个招呼。经典的打招呼环节。

NM-S00095 同学坚持在代码中使用中文逗号,促进了人类与编译器的文化交流,他才是真正的文化使者!

NM-S00102 同学正在尝试输出一句“我不会”。尽管如此,为了防止评测姬被这简短的三个字搞得一头雾水,他仍然耐心地将整个题面都复制了上来,共计 $552$ 行。



NM-S00160 同学在程序开头编写了一行较长的注释,似乎在向本场比赛的题目发起谴责。

截然不同的是,NM-S00167 同学似乎在注释中写下的是充满感激与热爱的文字,尽管笔者目前尚未查明 $\texttt{secoud}$ 的含义。

如果说上面两位同学发言的对象都是 CCF,那么 NM-S00192 同学则直接讲矛头伸向了考场周围的选手们。不论如何,这样恶毒的诅咒是我们应该深恶痛绝的。为了保持内蒙古人民一贯的高素质,笔者宣布将这位选手开除内蒙古籍。

是的,本场比赛的题目创死了很多人,或许也包括 NM-S00195 同学。

NM-S00208 同学也同样正在向世界打招呼。但不同的是,他似乎正在面临着是否退役的痛苦抉择。尽管我们无法确定他最终要如何选择,但似乎仍然可以在这里向他道一句 OIers 常用的告别祝福:祝好!

接下来就要进入笔者认为本文最有趣的部分了!
NM-S00251 同学完全不会做本场比赛最简单的 T1,代码内容仅包含一个输出“不会”二字的语句。

同时,我们也有理由怀疑 T2 和 T3 其实是两道非常经典的板子。在这位选手的不懈努力下,提交了一份足够美妙的答卷。让我们恭喜他在官方数据的测试中,取得了 $179$ 分($0 + 100 + 75 + 4$)的好成绩,位列内蒙古第 $5$ 名!
当然,或许是这位选手极其敏锐地注意到了评测姬的判题体验,为了防止评测姬在同一种编码下频繁地阅读代码导致的审美疲劳,他贴心地在 employ.cpp 中使用了 GB 2312 的编码格式,而其余三份代码则继续使用了更常见的 UTF-8。
幸运的是,评测姬果然没有辜负这片苦心,在这题中给他留了 $4$ 分的印象分。
另外,可能是出于同样的原因,他也在 road.cpp 中使用了 freopen 来进行文件读写,但在 replace.cpp 和 employ.cpp 中使用了 fstream。
但简单的文字描述总是不足以突出这份良苦用心的。为了能够足够深刻地理解这份作品,我们仍然需要认真鉴赏这位选手在代码中留下的注释。

已完成今日如果你看到这里了那我就可以告诉你一个惊喜大学习。
NOI 竞赛委员会主席杜子德先生曾在很多场合反复提到了一句话,即,做干净的奥赛。现实也雄辩地证明,这句话在各种比赛的论证后,成为了事实。尽管外界质疑声频频,笔者仍然愿意相信这位选手的实力,以及干净的奥赛。
不论如何,这位选手的代码仍然值得我们细细品鉴。
T1 club.cpp(UTF-8):
#include <iostream>
using namespace std;
int main(){
cout<<"不会"<<endl;
return 0;
}T2 road.cpp(UTF-8):
#include <bits/stdc++.h>
using namespace std;
struct FastInput {
static const int BUFSIZE = 1 << 20;
int idx, len;
char buf[BUFSIZE];
FastInput() : idx(0), len(0) {}
inline char nextChar() {
if (idx >= len) {
len = fread(buf, 1, BUFSIZE, stdin);
idx = 0;
if (len == 0) return 0;
}
return buf[idx++];
}
template <typename T>
bool read(T &out) {
char c = 0;
T sign = 1, val = 0;
c = nextChar();
if (!c) return false;
while (c != '-' && (c < '0' || c > '9')) {
c = nextChar();
if (!c) return false;
}
if (c == '-') {
sign = -1;
c = nextChar();
}
for (; c >= '0' && c <= '9'; c = nextChar())
val = val * 10 + (c - '0');
out = val * sign;
return true;
}
};
struct Edge {
int u, v;
long long w;
int mask;
};
struct DSU {
vector<int> parent, rnk, cityCnt;
DSU(int n = 0) { init(n); }
void init(int n) {
parent.resize(n + 1);
rnk.assign(n + 1, 0);
cityCnt.assign(n + 1, 0);
for (int i = 1; i <= n; ++i) parent[i] = i;
}
int find(int x) {
while (parent[x] != x) {
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
bool unite(int a, int b, int &cityComp) {
int ra = find(a), rb = find(b);
if (ra == rb) return false;
bool ca = cityCnt[ra] > 0;
bool cb = cityCnt[rb] > 0;
if (rnk[ra] < rnk[rb]) swap(ra, rb);
parent[rb] = ra;
cityCnt[ra] += cityCnt[rb];
if (rnk[ra] == rnk[rb]) ++rnk[ra];
if (ca && cb) --cityComp;
return true;
}
};
int main() {
freopen("road.in", "r", stdin);
freopen("road.out", "w", stdout);
FastInput in;
int n, m, k;
if (!in.read(n)) return 0;
in.read(m);
in.read(k);
vector<Edge> edges;
edges.reserve((long long)m + (long long)n * k);
for (int i = 0; i < m; ++i) {
int u, v;
long long w;
in.read(u);
in.read(v);
in.read(w);
edges.push_back({u, v, w, 0});
}
vector<long long> costTown(k);
for (int j = 0; j < k; ++j) {
long long cj;
in.read(cj);
costTown[j] = cj;
for (int i = 1; i <= n; ++i) {
long long a;
in.read(a);
edges.push_back({n + 1 + j, i, a, 1 << j});
}
}
sort(edges.begin(), edges.end(), [](const Edge &a, const Edge &b) { return a.w < b.w; });
int totalNodes = n + k;
DSU dsu(totalNodes);
int totalMasks = 1 << k;
vector<long long> addCost(totalMasks, 0);
for (int mask = 1; mask < totalMasks; ++mask) {
int lb = __builtin_ctz(mask);
addCost[mask] = addCost[mask ^ (1 << lb)] + costTown[lb];
}
long long answer = LLONG_MAX;
for (int mask = 0; mask < totalMasks; ++mask) {
dsu.init(totalNodes);
for (int i = 1; i <= n; ++i) dsu.cityCnt[i] = 1;
int cityComp = n;
long long mstCost = 0;
for (const auto &e : edges) {
if (e.mask && ((mask & e.mask) == 0)) continue;
if (dsu.unite(e.u, e.v, cityComp)) {
mstCost += e.w;
if (cityComp == 1) break;
}
}
long long total = mstCost + addCost[mask];
if (total < answer) answer = total;
}
printf("%lld\n", answer);
return 0;
}T3 replace.cpp(UTF-8):
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const ull BASE = 1315423911ull;
const size_t MAXLEN = 5000000 + 5;
const long long COMBO_LIMIT = 200000;
static ull pw[MAXLEN];
struct PairKey {
ull h1, h2;
int len;
bool operator==(const PairKey& other) const noexcept {
return h1 == other.h1 && h2 == other.h2 && len == other.len;
}
};
struct KeyHash {
size_t operator()(const PairKey& k) const noexcept {
return (size_t)(k.h1 ^ (k.h2 * 1000003ull) ^ ((ull)k.len * 19260817ull));
}
};
ull get_hash(const vector<ull>& pre, int l, int len) {
return pre[l + len] - pre[l] * pw[len];
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
pw[0] = 1;
for (size_t i = 1; i < MAXLEN; ++i) pw[i] = pw[i - 1] * BASE;
ifstream fin("replace.in");
ofstream fout("replace.out");
int n, q;
fin >> n >> q;
unordered_map<PairKey, int, KeyHash> mp;
mp.reserve(n * 2);
struct UP { ull h1, h2; int len; int cnt; };
vector<UP> uniq;
uniq.reserve(n);
auto hash_string = [&](const string& s) -> ull {
ull h = 0;
for (char c : s) h = h * BASE + (ull)(c - 'a' + 1);
return h;
};
for (int i = 0; i < n; ++i) {
string a, b;
fin >> a >> b;
int len = (int)a.size();
ull h1 = hash_string(a);
ull h2 = hash_string(b);
PairKey key{h1, h2, len};
auto it = mp.find(key);
if (it == mp.end()) {
int idx = (int)uniq.size();
mp[key] = idx;
uniq.push_back({h1, h2, len, 1});
} else {
++uniq[it->second].cnt;
}
}
for (int qi = 0; qi < q; ++qi) {
string s, t;
fin >> s >> t;
int m = (int)s.size();
if ((int)t.size() != m) {
fout << 0 << '\n';
continue;
}
int l0 = -1, r0 = -1;
for (int i = 0; i < m; ++i) {
if (s[i] != t[i]) { l0 = i; break; }
}
if (l0 == -1) {
fout << 0 << '\n';
continue;
}
for (int i = m - 1; i >= 0; --i) {
if (s[i] != t[i]) { r0 = i; break; }
}
int diffLen = r0 - l0 + 1;
long long combos = (long long)(l0 + 1) * (m - r0);
vector<ull> ps(m + 1), pt(m + 1);
ps[0] = pt[0] = 0;
for (int i = 0; i < m; ++i) {
ps[i + 1] = ps[i] * BASE + (ull)(s[i] - 'a' + 1);
pt[i + 1] = pt[i] * BASE + (ull)(t[i] - 'a' + 1);
}
long long ans = 0;
if (combos <= COMBO_LIMIT) {
for (int pos = 0; pos <= l0; ++pos) {
int minLen = r0 - pos + 1;
for (int len = minLen; pos + len <= m; ++len) {
ull hs = get_hash(ps, pos, len);
ull ht = get_hash(pt, pos, len);
PairKey key{hs, ht, len};
auto it = mp.find(key);
if (it != mp.end()) ans += uniq[it->second].cnt;
}
}
} else {
for (const auto& up : uniq) {
int len = up.len;
if (len < diffLen) continue;
int start = r0 - len + 1;
if (start < 0) start = 0;
int end = l0;
if (start > end) continue;
for (int pos = start; pos <= end; ++pos) {
ull hs = get_hash(ps, pos, len);
if (hs != up.h1) continue;
ull ht = get_hash(pt, pos, len);
if (ht != up.h2) continue;
ans += up.cnt;
}
}
}
fout << ans << '\n';
}
return 0;
}
//如果你看到这里了 ,那我就可以告诉你一个“惊喜 ”
//我不知道会不会有人看这个代码,工整吧
//半个小时 才写出来的
//这个没有road多
//我妈给我报的课我基本没上,纯跟AI学
//AI讲的可明白多了,还是1对1
//总之,看到的话不要惊讶
//昨天AI告诉我,可读的变量名可以让人读的更清楚
//我本来没打算这么写来着,但是有趣的是Deepseek严厉的批评了我
//所以特意去英语速成啦
//至于这个应该没人看见,因为是机器判题T4 employ.cpp(GB 2312):
#include <bits/stdc++.h>
using namespace std;
int main(){
ifstream fin("employ.in");
ofstream fout("employ.out");
long long n,m;
if(!(fin>>n>>m)) return 0;
string s; fin>>s;
for(int i=0;i<n;i++){long long x; fin>>x;}
fout<<0<<'\n';
return 0;
}//错了这个,就不整理了 NM-S00258 同学在代码中编写了一种崭新的算法,想必这位选手一定是博弈论的一把好手。

为了使评测姬对代码的理解更为深刻,NM-S00329 同学在 club.cpp.cpp 中为每一行代码都加上了(伪)编译日志,或许这位选手也可以被称为“人肉编译器”。


以上是本场比赛出现的所有迷惑行为。顺带一提,由于选手较多,共 $3446$ 份代码折磨了笔者一周时间,然而还是没能发现很多高质量的整活。希望接下来的高质量整活可以拥有更大的占比,至少让笔者看代码能有点成就感。
本文篇幅较长,如果你看到这里,笔者以 $(CSP2025)_{32} \%$ 的真诚感谢你的支持与耐心。
本文由 @RyanLi 撰写,如需撤下或投稿,请在洛谷向我发起私信。
后记
尽管 NM-S00251 的强悍实力让所有人都为之惊叹,但悲剧也随之发生。正当笔者决定交稿时,却接到了一位神秘选手的匿名投稿。没有任何配文,只有简单的一张图片:

怎么会是呢。