Day 1:
8:30:
睡懒觉,一觉睡到 8:30,“嘟嘟嘟”的电话声响起,迷迷糊糊睁开眼睛,快点,去成都七中……
没错,我连今天要考试都不知道(其实昨天老师给我发了消息的,只不过在学数学,没看),于是,坐出租车,一个人火速赶去……
路上可真堵,头昏昏的,想睡觉。
10:10
下车,进校门,直登 5 楼(不过是坐电梯),进了机房,人挺多啊,目测 50 人以上,找个靠窗户的位置坐下。
先看题,总共 4 题,T1 是个构造题,T2 看数据范围应该是个 DP,T3 看这题目背景应该是个模板(脑袋仔细回想了一会儿,嗯对,没学过),T4 跟区间有关系,目测是个线段树。
看题+理解题意耗时 20 分钟。
10:30
权衡了一下,先写 T4,其题目大意是:
给出一个序列,然后给出多个询问,每个询问给出多个区间,每一个区间求范围内的最小公倍数,然后输出这些区间答案的最小公倍数。(答案对998244353取模)
看起来很绕,其实比较好理解, 我的初始思路是:直接维护一个线段树,每个节点存的是区间的最小公倍数,嗯对,就这么 easy!
看了看数据范围,诶,线段树貌似可以直接 A 掉这题,嗯对,样例过了,大样例呢?找了半天没找到,等老师过来传一下。
11:00
T4 写完了,准备写 T1,是个构造题,题意如下:
有多个骰子,每面都有一个正整数(在 [0, 10^6 ] 以内),每个骰子的六个面上数字两两不同,然后在给出一个正整数 k,要求同时投出所有骰子,所有骰子朝上面上写有数字的异或和都是 k 的倍数。(要求构造每一个骰子上面的数字)
看到异或了,可以考虑每一位的贡献,感觉可以 Trie 树来拆位考虑,写了 20 多分钟,后面发现,构造序列之后,验证答案的时间复杂度是 O(6^n),直接就爆掉了,感觉分还不如根据性质分类讨论分多,连忙删掉代码,考虑重构……
发现测试数据集 1 满足 n = 1,有着 10 分,这样直接输出 k 的倍数就行,但是得特判一点儿,k 的 6 倍如果大于 10^6,那么也是不满足的。
然后还有一个数据集满足 k = 2,想了想,2 的二进制位为 10,感觉可以 1 2 的直接输出。
这样好像 30pts 了,看 T2。
11:35
老师回机房了,过去要大样例,回过头来看 T4,测了一下,诶,怎么不对!调试了几分钟,猛然醒悟:
这个式子是并不成立的,对于取模后的结果,再取最小公倍数,有大概率是错的,就像:
上述的式子一样,除法也是不成立的,在这种情况下我们可以用费马小定理或者扩展欧几里得(exgcd)来求逆元,使得等式成立,但是对于求 lcm 的情况,逆元貌似莫得用,想不到什么好的办法,就觉得不用改了,希望能骗点儿分。
然后再看 T2,不过 11:50 就交了,感觉这点儿时间推不出来 DP 的式子,于是转手开始打暴力,题意大概是这样:
有着一个长度为 n 的序列,每一个数字 ci 表示这种颜色,可以将这个序列给切开(想多少段就多少段),然后求这切开后序列的最大美丽值,以及切最大的段数,以及每段的起点和终点。(一个序列的美丽值为每段的 mex 之和)
一个集合 S 的 mex 定义为最小的没有在 S 中出现的非负整数。
数据范围挺大的 50 万级别的 n,数据好像不是捆绑测试,那行,对于 n <= 22 的数据,直接爆搜,看是否从此点切开,每次有两种选择,复杂度为 O(2^n),加了点玄学剪枝。
然后看数据,有个测试集为 ai<=1,这样每段我们求 mex 会发现,如果这一段既有 0,又有 1,那么贡献将是 2,所以 1 我们尽量选连续的 1 使得贡献为 0,因为选了 1 之后没选 0 的话贡献是 0,这样就少了。
所以我们尽量多选 0 和 1 在一起,否则不选 1,只选 0,这是考场策略,不过样例集里好似没有这个特殊性质的,所以自己手推一下就收尾了。
11:50
老师已经喊收卷了,T3 一行代码都没敲,因为题目要求不是捆绑测试,而且输出是 YES 或者 NO,不过 YES 要多输出路径的并(这个等会儿讲),所以直接一个 puts("NO") 结束。
嗯,考了一个半小时,收拾东西,出去吃饭。
12:10
领队老师带我们去了附近一家很火的面馆,我点了一个二两面,结果端出来一看,就这么点儿,只够垫点儿肚子的,然后看了看学长点的三两,额,跟我们家那边一两差不多,还贵了 8 块钱(这里小小的吐槽一下)。
吃了几下,就干完了,立马“杀”向机房,准备改题,结果一问,结果还没有出来,于是去做了做线段树的题目。
14:00
机房巨佬 meatherm 匆匆忙忙的跑了回来,手上拿着 U 盘,将成绩与排名发给了所有人,打开一看,挖草,竟然有 4 人 AK 全场!
密密麻麻的人头,我人呢?Ctrl+f 网页搜索,啊,怎么跑后面去了,不是吧,怎么才 10 分!!!
连忙一看,啊这,就只有 T1 的 10pts,怎么会?
看 T1 的另外一个特殊性质点 k=2,发现因为每一个骰子的六面数字要相同,我这 1 2 有相同的,直接就给 WA 掉了。
然后看 T2 的特殊性质点,全部 WA 了,发现不能直接选 1 的连续区间,得在左右两边有 0 的情况下,保留左端点或者右端点,这样可以得到一个 2 的贡献。
然后看 T3,TMD,居然没有一个是 NO,数据里全部都是 YES,真的黑啊!
再看 T4,所有测试点都有超过 mod 的,线段树直接挂掉了,还不如直接高精度呢,这样子至少能有个 30pts。(其实我那也没时间写了)
14:30
由巨佬 meatherm 和 nch 进行讲题,同时,他俩也是 AK 的人之一,先讲 T1,说了一大堆,最后说很简单,代码几行就搞定了,有亿点点没听懂。
然后是 T2,讲了一种 dp 做法,感觉懂了,写了一个 n^2 的 dp,然后优化就没搞懂了。
之后先讲的 T4,首先就是说明了线段树做不了这题,然后考虑根号分治,然后进行分块,然后在分块里面再分块,然后就没有然后了……(我还是不懂啊!)
最后讲 T3,其实这题是个网络流问题(什么东东,没有学过的悲哀)……(听不懂)
好了,讲完了。
15:20
题目讲完以后,一题都不好改,那就干脆不改了,继续去做线段树的题目了。
然后写了一个线段树二分,险而又险,勉强卡过,然后就下课了……
Day 2:
今天做好了准备,只迟到来了 3 分钟到考场。
8:35
打开文件,先阅题,T1 的描述有些长,有些没看懂,T2 感觉应该是个数学题,T3 是变形模式下的最长上升子序列,T4 看到操作有“回到第 T 次操作后的状态”,感觉是可持久化的数组。
感觉 T3 好写一些,先写 T3。
9:00
T3 题意大概是这样的:
给出 n 个区间(li,ri),将 li 到 ri 的数字按照顺序加入数组,然后求这个数组的最长上升子序列。
看起来挺简单的,但是这 li 和 ri 都很大,如果暴力去做的话就好像只有 10pts,赶紧推式子,设 fi 表示数 i 结尾的最长上升子序列。,然后每次加入一个区间时,有三种情况:
- i > r:则没有转移
- i < l:fi + r - l +1
- l < i < l:fi + r - i
这样时间复杂度是 O(n * max(ri)) 的,过不了大样例(一直卡着), 但是应该能得 30pts,于是去看 T1。
9:30
T1 题意很长,有点儿绕:
有 n + 1 个通讯站是好的,有 k 个通讯站是坏的,每一个通讯站都有一个坐标 (xi,yi),编号从 0 到 n + k,好的通讯站可以传送信号(向同一个轴方向传播),也可以接受信号,坏的通讯站只能接受信号,不能传送信号,假设传播信号不需要时间,而接受信号要 1 的时间,0 号通讯站是主站,它可以制造信号,制造和传播信号需要 2 的时间,求 0 号主站将信号传播到多个询问的通讯站需要最少的时间是多少?
这题,我看了半天,才发现,这是一个图,对于一个轴的通讯站,进行连边的操作,这样就是一个图了,然后求 0 点到其他店的最短路径,不就是单源最短路径嘛,直接手写 dijstra 算法,时间复杂度为 O(n log n) ,这不直接就过掉一题了,然后看 T4。
10:20
T4 看起来也像一个模板,大意是:
有一颗 n 个节点的树,每一个节点有着 (Li,Ri,Vi) 这个三元组,有着 3 个操作,第一个就是将节点 x 号的 (Li,Ri,Vi) 变为 (Li`,Ri`,Vi`);
第二个操作是创建一个长度为 n 的序列 a(初始全 0),询问在以 x 号节点为根的子树中,对于第 i 个节点,将 a 序列的 Li 到 Ri 区间增加 Vi ,然后给出 a 序列中 L 到 R 区间的和。
第三个操作是回到第 T 次操作后的状态。
这题我可以直接按照题意,先建树,然后建一颗线段树维护 a 序列的区间,有着区间查询,区间加法等操作,在操作 2 时,我们可以深搜一遍树,找到 x 号节点,依次进行 add 的累加,在操作 1 时,可以直接 O(1) 时间在数组里进行修改。
对于操作 3,我的考场思路很暴力,记录一下第 k 次操作是否是 1 号操作(因为只有 1 号操作是会变的),如果是,再记录一下第 k 次操作的节点原来的权值([Li,Ri,Vi]),然后从当前操作开始,逐渐向 T 号操作遍历,如果有 1 号操作,就进行赋值。
这样就实现了此题了,中间线段树写废了一下,调试了一下,小样例过了,大样例一直卡着,估计超时了。
感觉这样也能拿 30pts 了,于是回过头来看 T2。
11:20
T2 描述很简单:
给定两个长度为 n 的序列 a,b,可以进行任意重排,求出最大字典序的 c,其中 。
刚开始我先考虑只用重排序列 b,思路为,对于 ai,求出 的值,然后在 b 中查找这个值(可以二分查找) ,这样组合起来可以凑成最大的字典序 c,然后我这样写小样例过了,大样例没有过,感觉写暴力(组合数为 C(n*2,n),暴力起来太大了)可能还没有我这样写这个只用重排 b 的快嘛。
于是考试结束,在机房窝了半个小时该题,干饭喽~
12:25
因为今天出来的时间比较晚,没有和学长们一起吃饭,于是,我前往了“汉堡王”,点了一个单人套餐,这总比吃面划算多了嘛~
13:10
回机房了,人很少,听别人聊天我才知道今天上午的考试是和杭二一起考,浙江很卷的,现在巨佬们正在评测。
中午跟 Neil_Qian 聊了会儿天,发现我的思路 T1 过不了,因为可能有许多点在同一行或同一列,这样的话复杂度降到了 O(n^2),这样应该是 90pts。
于是继续去练线段树的题目,静静等待成绩的公布。
15:00
巨佬 meatherm 回来了,经过评测,咱们成都七中最高分 198pts,由于评侧机的编译器版本过低,很多代码没有过编译,于是在调。
我又做了一道线段树的离散化题目,然后去看线段树的区间合并。
16:00
成绩出来了,这一看,惊呆我的下巴,不是吧,怎么只有 20 分?我一看 T1 有着 10pts,T2 爆 0,T3 也是 10pts,T4 爆 0。
T1 不是差点优化就正解了吗?怎么会是 10pts 呢?用测试数据试了一下,有环的情况下,竟然卡出了,后来一看,怎么会,后面看函数,写的是堆优化的 Dijstra 算法,发现堆开的是大根堆,在有环且权值一样的情况下,一直在环上走,emm……
然后是 T2,爆 0 不出我所料,不过 1 分都没有骗到,有点儿可惜……
T3 第一个样例点过了,第 2 个显示超时,是哪点没有优化到吧……
T4 我感觉应该能拿点分啊,结果显示的是运行时错误,好像是不能用 auto 这个东东。
然后发现前 30 名好像都被杭二霸榜了,最高的也是直接 AK 全场,然后第二名 380,去官网查了一下,人家才初二……
16:30
看题解,T1 说的思路和我的差不多,要考虑优化:
每一行和每一列建立一个虚点,然后在这一行或者列的点超对应行或者列的虚点连边,边权为 0;
虚点再向这一行或者列对应的点连边,边权为 1。
这样就实现了连边,但是边的条数仍然是级 n 别的。
T2 的贪心策略有些没看懂……
T3 的 DP 式子和我是一样的,但是有着一层优化,选了一个区间,就一定要选它的右端点,否则不是最优的,所以说结尾点 i 就只有 n 个,这样复杂度降到了 O(n^2),然后可以用线段树进行一个维护,复杂度降到了 O(n log n)。
T4 的题解看的我一脸懵逼,什么鬼,竟然要面对数编程,对于不同的数据,还有不同的算法,什么主席树啊,分块啊,散块啊,莫队啊……(我都不懂啊!不过我这样写确实能拿 30pts 的)
总结:
细节啊细节,一定要关注细节,一不小心,掉坑里面了,然后呢,本来的高分呢,瞬降,然后,不就无了?