本文同步发表在洛谷专栏,你也可以点击这里以获得更佳的阅读体验。下面是往期的迷惑行为大赏:


喜报,今年已经是内蒙古(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.inpalygon.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.inpoker.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.cppemploy.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 的强悍实力让所有人都为之惊叹,但悲剧也随之发生。正当笔者决定交稿时,却接到了一位神秘选手的匿名投稿。没有任何配文,只有简单的一张图片:

怎么会是呢。

最后修改:2025 年 11 月 14 日
如果觉得我的文章对你有用,请随意赞赏