NOI2023 游记(打工人视角版)

· · 生活·游记

换了视角的赛场 依然热血澎湃 祝选手们好运吧 命运的草蛇灰线早已埋好 而键盘上飞扬的都是每个人独一无二的青春 虽然作为一个既得利益者这样说多少有点不负责任 但这段旅程依然是很梦幻的(间歇性的噩梦也算是梦吧) 加油吧我的朋友们

——寒雨微凝

流水账预警!大量 NOI 无关内容预警!

为什么这篇游记甚至比我在役时期所有游记都长啊?

7.5 起点

小学期的写完第一个大作业的晚上,舍友 hywn 突然问我想不想去NOI,于是果断退掉了3-5周的交叉实践课。

NOI,OIer 的盛会,多么令人神往的赛场啊!

7.8-7.10 验题

第一次正经验题居然是给 NOI 验题,我何德何能。。。(好在目前来看没有出锅)

拿到 string 后紧急上 oi-wiki 补习后缀数组,在草稿纸上画了若干个长条(代表字符串),然后发现题目就是板子拼了个二维数点,需要细心一点减去多算的情况即可,感觉适合放 D1T2 或者 D2T1,没想到最后被放了 D2T2。

放个验题代码,其中 SA 部分怕写错,直接粘了以前写的板子

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
namespace FGF
{
    const int N=2e5+10;
    int sa[N],h[N][20],rk[N],cnt[N],tp[N],m,lg[N],Q,n,nn,ans[N];
    char s[N];
    struct Tree1{
        int a[N];
        void add(int x,int v)
        {
            while(x)a[x]+=v,x-=x&(-x);
        }
        int ask(int x)
        {
            int sum=0;
            while(x<=n)sum+=a[x],x+=x&(-x);
            return sum;
        }
    }t1,t2;
    struct Tree2{
        int a[N];
        void add(int x,int v)
        {
            while(x<=nn)a[x]+=v,x+=x&(-x);
        }
        int ask(int x)
        {
            int sum=0;
            while(x)sum+=a[x],x-=x&(-x);
            return sum;
        }
    }t3;
    struct ques{
        int x,id,v;
        ques(){}
        ques(int _x,int _id,int _v):x(_x),id(_id),v(_v){};
    };
    vector<ques>q[N];
    vector<pair<int,int>>op[N],q2[N];
    void init()
    {
        memset(h,0x3f,sizeof(h));
        memset(rk,0,sizeof(rk));
        memset(sa,0,sizeof(sa));
        memset(t1.a,0,sizeof(t1));
        memset(t2.a,0,sizeof(t2));
        memset(ans,0,sizeof(ans));
        m=30;
        for(int i=1;i<=n;i++)
        q[i].clear(),q2[i].clear(),op[i].clear();
    }
    void radixsort()
    {
        for(int i=1;i<=m;i++)cnt[i]=0; 
        for(int i=1;i<=n;i++)
            cnt[rk[tp[i]]]++;
        for(int i=1;i<=m;i++)
            cnt[i]+=cnt[i-1];
        for(int i=n;i;i--)
            sa[cnt[rk[tp[i]]]--]=tp[i];
    }
    void SA()
    {
        for(int i=1;i<=n;i++)
            rk[i]=s[i]-'a'+1,tp[i]=i;
        radixsort();
        for(int l=1;l<=n;l<<=1)
        {
            int num=0;
            for(int i=n-l+1;i<=n;i++)
                tp[++num]=i;
            for(int i=1;i<=n;i++)
                if(sa[i]>l)tp[++num]=sa[i]-l;
            radixsort();
            memcpy(tp,rk,sizeof(int[n+1]));
            int p=1;
            rk[sa[1]]=1;
            for(int i=2;i<=n;i++)
                rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&(sa[i]+l<=n&&sa[i-1]+l<=n&&tp[sa[i]+l]==tp[sa[i-1]+l])? p:++p);
            if(p>=n)break;
            m=p;
        }
    }
    void getheight()
    {
        int k=0;
        for(int i=1;i<=n;i++)
        {
            if(rk[i]==1)continue;
            if(k)k--;
            while(s[i+k]==s[sa[rk[i]-1]+k])k++;
            h[rk[i]][0]=k;
        }
        lg[1]=0;
        for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
        for(int j=1;j<=17;j++)  
            for(int i=1;i+(1<<j)-1<=n;i++)
                h[i][j]=min(h[i][j-1],h[i+(1<<(j-1))][j-1]);
    }
    int LCP(int l,int r)
    {
        l=rk[l],r=rk[r];
        if(l>r)swap(l,r);
        l++;
        int k=lg[r-l+1];
        return min(h[l][k],h[r-(1<<k)+1][k]);
    }
    void work()
    {
        scanf("%d%d",&nn,&Q);
        scanf("%s",s+1);
        init();
        s[nn+1]='z'+1;
        n=2*nn+1;
        s[n+1]=0;
        for(int i=1;i<=nn;i++)
            s[n-i+1]=s[i];
        SA();getheight();
        for(int i=1;i<=Q;i++)
        {
            int x,r;
            scanf("%d%d",&x,&r);
            q[x].push_back(ques(x,i,1)),q[x+2*r].push_back(ques(x,i,-1));
            q2[x].push_back(make_pair(x+r-1,i));
        }
        for(int i=nn;i>=1;i--)
        {
            for(auto j:q[i])
                if(i&1)ans[j.id]+=j.v*t1.ask(rk[j.x]);
                    else ans[j.id]+=j.v*t2.ask(rk[j.x]);
            if(i&1)t2.add(rk[n-i+1],1);
                else t1.add(rk[n-i+1],1);
        }
        for(int i=1;i<=nn;i++)
        {
            int l=LCP(i+1,n-i+1);
            if (s[i-l]<s[i+l+1]||l==0) continue;
            op[i-l+1].push_back(make_pair(i,-1));
            op[i+1].push_back(make_pair(i,1));
        }
        for(int i=1;i<=nn;i++)
        {
            for(auto j:op[i])t3.add(j.first,j.second);
            for(auto j:q2[i])ans[j.second]+=t3.ask(j.first)-t3.ask(i-1);
        }
        for(int i=1;i<=Q;i++)
            printf("%d\n",ans[i]);
    }
}
int main()
{
    freopen("string.in","r",stdin);
    freopen("string.out","w",stdout);
    int Tid,T;
    scanf("%d%d",&Tid,&T);
    while(T--)FGF::work();
    return 0;
}

Day0 7.21

早上验收大作业,不久后收到原本 17:30 的航班晚点到 19:30 的消息,午睡起来两点多又收到航班晚点到 20:30 的消息,果断决定改签,没想到联系完 CCF 后,行程里直接多了一张机票,CCF 好有钱!(后续:已经收到原航班退票的消息)

满心都是假期开始的欢喜,在首都机场第一次吃到了滑蛋吐司,好评;机场过安检后居然没有奶茶店。第一次线下见到神仙 EI。

十点多落地,先等行李,再等了半小时接机。23:40 终于到酒店,感觉发的物资也很棒(成都七中的熊猫挂件好像兔子)。房间第一眼好评,没想到洗澡的时候漏水严重。1点终于睡了。

Day1 7.22

6.40 起床,7:20 出发去学校印卷子。学到新知识:出于保密需求,版纸也要撕下来带走/销毁。

快 13:00 下班,在食堂吃午饭后回酒店。下午 15:00 上班,五个人流水线工作,装订纸质题面,打包题面到信封里,并贴上密码条。我负责了密码条粘贴,所以 day1 几乎每个人的密码条都是我亲手贴上去的!然后分区按座位号手动 sort。大家各显神通,分别使用了插入排序、归并排序、桶排序等多种算法。战况如图(信封封口处的双面胶和密码条贴纸)

五点多干完大部分活,和舍友出发去春熙路看阿波罗尼亚,第一次体验小剧场看音乐剧!一路坐地铁非常顺利,完全没等车!车上查吃饭的地方,在网红店陶德砂锅线上排号,到店后等了 10min 就到我们了,点了青豆肥肠、蒜蓉虾仁,都很好吃

原以为 19:30 的演出 19:15 吃完,19:20 到正好,没想到演出其实是 19:00 开始。。。但现场效果真的震撼,这几天脑子里已经单曲循环《我的家族》了 ,mia 的魅力!没想到演出后的抽奖居然抽到了 380 的增票,太离奇了!可是我 28 晚上就要离开成都(哭

Day2 7.23

早上看开幕式,有幸在签名墙上留下自己的名字。

交响乐、川剧变脸、舞蹈表演好评!小姐姐好美!小哥哥好帅!唱歌的节目对耳朵不太友好,感觉应该音响开小点的,美声唱法本来就是不需要拿麦克风的啊。陈睿作为成都七中校友为 NOI 送祝福,全场鼓掌!但是没想到介绍嘉宾的时候把学生专家名单直接放在了大屏幕上,有效保密,出会场的时候已经听到选手讨论 EI 是不是出题人了。

下午监考笔试+练习赛,查身份证的时候见到了所有认识的学弟学妹,开心!事实上,监考×,考场服务员√,一直跑来跑去给选手递水。发现练习赛期间教练居然是可以进场的,董先森一直在考场里转悠。之前老师说从来没见过这么多女生来打工,看了看今年来 NOI 的女选手也很多(不知道是不是推行 NGOI 的缘故),而且非常团结,笔试都抱团坐在一起。总之学 OI 的姑娘在变多,这是好的!

下班后,约了高中同学 wzy 一起去逛川大,并把赠票送给他,一路走一路聊,走累了就在江边坐了一会。见面之前其实有点担心会不会无话可说,毕竟中学时我们两个其实不怎么熟,结果没想到会聊得很好。我们交流了一下彼此的上大学后要学的课和不同城市的生活体验。后来他说我“号练得很好”,说我的生活非常健康,说我不卷是因为“卷成为一种习惯”。首先感谢他这么高的评价吧。在华子待久了真的深深明白自己的弱小(其实学 OI 的时候多少已经感觉到了),时常觉得自己不够聪明更不够努力,身边太多卷王大神了。但是在我已经接受自己的平庸和弱小的时候,突然得到曾经的同伴的肯定还是很开心的,大约我也没有那么差也不是完全不好好学习。至于说我生活健康,大约只是我休闲娱乐方式比较养生,并且一直有坚持运动吧。

总之聊得很愉快,但是晚上没有吃饭,回去路上地铁方向还坐反了,到房间后很饿,于是啃了飞机上带下来的面包。

Day3 7.24

NOI Day1!

早八监考被迫早起,七点准时到达酒店餐厅但是似乎饭还没好,差评。

开考后跑来跑去试图帮选手解决问题,但是由于不会技术+NOI 参赛经历快忘光了+第一次见 selfeval,感觉自己除了当服务员和允许选手上厕所外解决不了任何问题,遂满场寻找 yyl 求助。学会了 top+kill 解决 selfeval 卡死的问题,还是有一点长进的!

查身份证的时候发现仅 A 区就有好几个 09 年的选手,瞬间感觉自己已经老了,现在的小朋友们好厉害啊!

不得不说赛场真的很有感觉,最后 10min 的时候全场似乎都进入了一种紧张感拉满的状态,我也被代入进去,仿佛这也是我的赛场。

考试结束前 0.5h 的时候,突然有选手问桌面上的信封是什么。考完收试题的时候,我们发现近一半选手根本没有打开试题信封!于是我们不得不自己一个个拆开自己封上的信封,原本为选手准备的仪式感完全转化为工作量给到自己了,难过。希望明年不要这样了。收草稿纸的时候发现草稿纸具有很强的多样性,有些选手的草稿纸已经团成了几个球,有的选手会在草稿纸上完整写下自己的思路,仿佛一篇纸质题解,比我的笔记写得还整齐。

15:00 选手进来查分,果然遇到了教练来看学弟学妹的分。犹豫了半天要不要上去打招呼,最后在她找不到测试数据的时候站在她身后说了一下路径,但她似乎没听出来是我。快到 16:00 的时候突然意识到,密码条跟着信封被放在桌面上的一个问题是,任何人都可以看到任何选手的分数,毫无隐私性可言,那么只要有一个人遍历所有机器,就可以获得一个 ranklist(雾)。

原计划用监考的 5h 刷出一个大于拉练 4h 的微信步数,但是没考虑到散步和拉练的步频差距过大,最终在考试结束时步数刚过 2w,远小于拉练。于是决定下班后继续出去逛(其实是想去找好吃的),坐地铁到人民公园站,先骑车到陕西路吃蹄花,再绕到石室中学吃贺记蛋烘糕,然后穿过人民公园,到宽窄巷子人挤人,出来后不小心走错到了西安路上,意识到错误后回到枣子巷, 走到尽头后买了几个桃子就从中医大省医院站坐地铁回酒店了。中医大省医院站是很少见的有三个地铁线的换乘点,构造有点复杂,我在里面反复走错。。。宽窄巷子人真的真的太多了,摩肩接踵毫不夸张,感觉人流量是去年来的时候的两倍。

最终成功刷出大于拉练的微信步数,乐。

Day4 7.25

选手的休息日,Day2 题面的印刷日。

九点出发去学校,紫发被老师夸了,非常开心。刚开始没我什么事,于是和 hywn 去嘉年华逛了一圈,不想排队所以没有玩任何项目,遂决定去逛校园。边走边感慨南方的学校绿化真好啊,而且成都七中校园里居然有红旗和舞东风两个连锁超市,感觉自己每次去别的中学都像进了大观园(某附中你反思一下)。和 hywn 一起在选手签到的签名墙上拍照打卡。

9:50 回去干活,今天的印刷熟练了不少,任务量也少了三分之一,10:45 就带着题面回酒店。11:00 左右开始化身印度女工开始做手工,今天的打工人人数增加到了 8 个,于是开了两条 pipeline,效率\times 2 ,我仍然负责粘贴密码条。虽然中间闹出了小乌龙让所有人虚惊一场,但整体还是很顺利的。12:40 左右出发去吃饭,吃完大家集体点了奈雪,回去午休。

下午四点半,根据我的提议,5 个人一起去川大附近吃酸菜豆花,好吃不辣,锅底配料极其丰富,人均 40r 根本吃不完。吃完本想去逛川大,但没想到仅仅隔了两天就进不去了,只能在门口拍照打卡。然后去春熙路寻找网红大熊猫,刚打卡完就发现天气不太对,一查天气预报半小时后下大雨,于是火速往回赶,结果出地铁时没带伞的同伴们还是被淋了。(感谢 wzy 告诉我在成都出门最好带伞!)

Day5 7.26

NOI Day2!

大概是第二天了,不怎么出现奇奇怪怪的问题了,今天跑来跑去大部分都是允许选手上厕所,夹杂少量送水、送草稿纸。看到举手就赶过去解决问题,有时候会希望自己可以分身,莫名感觉有点像打地鼠(雾)。不过有一说一今年所有志愿者在看到举手时几乎都是快走或跑过去的,我也有一排排依次走看有没有举手举得比较低的选手被漏掉,所以响应速度应该还不错吧。但还是建议选手们举手举高一点,至少要超过挡板高度吧,不然坐下的时候真看不见,5h 如果一直站+走还是挺累的。后来发现有些选手去厕所时直接站起来就走了,完全没有征求监考员同意的意思,已经进化出了较强的自我管理能力。。。(还是不建议这么做)

没什么事干,又不敢站在选手身后看题看代码,于是趁一个选手去上厕所的时候看了他机子上的题面,试图做 T1。思考 30min 后发现自己题看错了。重看题后在草稿纸上画了一棵二叉树辅助思考,不久后被 yyl 发现并制止,以免我不小心把自己的草稿纸发给选手。把草稿纸塞进包里后继续空想,发现没有图完全想不明白,遂放弃思考。有一瞬间我真希望自己还是选手,能够在电脑前全身心地投入思考,能够随心在草稿纸上写写画画,能够让思维的火花飞扬在键盘上,能够再享受一次 NOI 赛场的热血……真令人着迷啊,一年的 OI 之旅太短太短了。

十二点多换班去食堂吃饭,刚开始吃的时候外面突然下大雨,我们开始担心怎么回去。结果吃完以后雨停了,但回去路上突然又开始下大雨,于是冲回考场。考试结束倒计时时,试图抓拍一张“剩余时间 00 时 00 分 01 秒”的照片,但是失败了,只有这个

快两点初步测完,yyl 让我和 hywn 去检查各自验的题有没有选手得分不符合预期(指省队队长没过签到题这种,以防数据锅了)。我才知道原来选手代码是可能会被看到的。 看了十几个选手的代码,似乎有很多特殊性质 A 写了但挂了的,然而我自己验题的时候就不知道这个性质怎么用,选手代码也没怎么看懂/kk。后来 yyl 说我们没必要帮选手 debug,所以我就没管了。两点半的时候我看外面只有 25℃,就想着在成都七中的田径场上跑步打卡(平等地酸每一个有标准田径场的中学),并且专门按 NOI2021 前的配速跑了 1500,虽然又潮又晒完全跑不动,但体感还是比那时候轻松多了,跑完后都不怎么喘。总觉得我参加过的这两年 NOI 冥冥之中形成了某种呼应:同样暴雨和暴晒随机切换的天气,同样令人难受的 98% 的湿度,同样 Day2 在比赛的学校里跑步(不过当年体力不太行只冲了个 1min30 的 400),同样不会做 D2T1,同样认识了很厉害的新朋友,NOI2021 前集训认识的学妹今年恰好也是高二 Ag,同样很高的队线,同样的兴奋感与神圣感……

三点查分申诉,几个学弟学妹都考得不太好,我忍不住走到他们身边,却又不敢和他们说话,也不知道能说些什么。这个赛场太残酷了。后来我看到教练在和 LCA 学长说话,就上前打了个招呼,于是 LCA 终于知道我是他同校学妹了。。。快 5 点的时候我们拍了合照,感觉拍照还是要找女生,出片概率较大,尤其是化了妆的小姐姐。

然后出发聚餐叶婆婆钵钵鸡,五香味的感觉比去年在乐山吃的更好吃了,红油味的还是和乐山的一样好吃,藤椒的也不错,吃完再次去了奈雪,等餐的时候又开始下大雨,我们在店里躲了一会最后还是冒雨回酒店了,好在这次大多数人都带了伞。

晚上我开始写这篇游记。从 sys 那儿得知今年的金银牌线高得可怕,在升学政策越来越差的情况下选手平均水平居然还能提高也是很神奇。

又一年 NOI 落幕了。

后记

后面几天都是出去玩,和 NOI 没什么关系所以就不再赘述了。感想是成都的天气好神奇,似乎能在北京的晒和浙江的潮之间随机切换,以及我爱冰粉钵钵鸡豆花蹄花冒烤鸭肥肠粉蛋烘糕!

21年曾许愿能再来 NOI,今年终于实现了。这几天我有幸认识了 yyl,zyb, EI, Itst, LCA 这些曾经取得过出色成绩,如今又回来为 OI 发光发热的选手(曾经传说中的名字出现在面前还是很神奇),在和他们的交流中我对 OI 比赛的理解加深了很多,也了解到一场场比赛背后有多少努力付出,很羡慕他们能深度参与 OI。因为我的 OI 时光太短,OI 于我像一场梦,我于 OI 似是过客。当然更多的是对他们的钦佩与感谢,有一代代这样的 OIer 在,可以期待 OI 会变得更好吧。我又想起了《写给OIer们的一些话》:

我们终究探索出了一条从未走过的路,那便是以 OIer 本身为主导的 OI 模式!

这样的模式是偏向于“用爱发电”的,它的核心基础是 OIer 们对 OI 本身持久的情怀

总之,这是一次很难忘很珍贵很有收获的经历,希望之后还能有机会去 NOI。感谢 hywn 让我有机会来,感谢所有人的付出。