NOIP模拟赛总结&题解
游记与总结
这场比赛是我做的所有“NOIP模拟赛”中最简单的了。。。
由于gls反复叮嘱要好好做,于是我就没有好好做(狗头),导致被全场吊打。
最开始没打算打,从szm电脑上看了看题目,发现T1没看懂T3T4不会,但是10s口胡T2,这时候gls命令我参加,于是我就报名了比赛并开始了被吊打之路。
开场先把T2敲了,但是Fhqtreap居然没有一次写对,RP--。切掉T2之后发现T3是个计算几何,果断弃掉,然后发现T4是个字符串,于是就开始撕烤T4(别问我为啥没做T1,问就是不会做)。
猜了个结论,感觉很对,于是口胡出 \(O(n^3)\) 的做法,发现只有 \(38pts\),不得已只能继续想,突然发现由于贡献是一段区间,所以可以线段树(没想到单调栈就是纯菜)。
于是莽了一发 \(O(n^2\log n)\) 感觉 \(65pts\) 很稳,于是就打算弃赛了。这时候gls进来给我们解释T1题意,借此我提出强烈抗议,请求删去T1这种垃圾题。
最后在gls的帮助之下,我切掉了T1,到了 \(265pts\),冲上了榜一。
感觉这次比赛自己的一次正确率还行(除了T1那种垃圾题以外),T2T4的正解/暴力都是一次过的。
题解区
垃圾题一道,就是一个读题题,也没啥好讲的,唯一有意义的就是当模数不为质数时的快速求逆元。
法一:exgcd
\(Ax=1\mod p\) 可以转化为 \(Ax+Bp=1\),然后就是板子了
法二:欧拉定理
\(Ax=1\mod p\) 可以求得 \(x^{\phi(p)}=1\mod p\)
这场比赛的签到题,发现前 \(N\) 项和后 \(N\) 项不管怎么删一定都有分界点,在这个分界点以前的是删完后的前 \(N\) 项,以后的是删完的后 \(N\) 项。
枚举分界点,然后前面保留最大的 \(N\) 个数,后面保留最小的 \(N\) 个数,动态维护。暴力 \(O(n^2)\),用平衡树/优先队列都可以优化到 \(O(n\log n)\)。
毒瘤计算几何,思路并不难(cy10秒切了)(cy:你毒瘤吧)
但是(可能是我写的难看)码量惊人,大概思路就是这张图:
显然在删掉大凸包上一个点的时候,有用的点之后可能是大凸包上的其他点以及小凸包上的一些点,所以我们先求两遍凸包把大凸包和小凸包都求出来。
然后我们可以发现,有用的小凸包上有用的点就是大凸包删除的点左右的点关于小凸包想切点,然后算面积就直接把它拆分成三角形用叉积算面积。
如何找到切点:我们可以发现,在大凸包上的每个点关于小凸包都有两个切点,如果我们分别考虑的话可以发现切点是单调的,所以我们就双指针一下分别扫出每个点对应的切点即可。
如何计算每一个区间的面积:先解释一下区间的面积是啥,那张图其实不是很完整,因为那两个点看上去在同一条直线上,如果不在的话我们失去的面积就是三个三角形减去两个切点之间的面积。
区间的面积我们可以用一个类似双指针的方法求出,容易发现区间的左右端点都是单调的,所以我们可以直接移动左右端点。
细节:
1.如果建完大凸包后就没有点,就不用建小凸包了,直接计算即可。
2.如果切点和被删掉的点关于那两个点的直线在异侧,那么这个切点根本没有发挥用处,我们可以直接再大凸包上减掉一个三角形,一定要记得特判这种情况,至于如果用叉积判断请自行撕烤。
3.在计算小凸包上一个区间的面积的时候一定要记得特判L,R之间的距离有没有超过凸包的一半。
然后这题就被愉快的切掉了。。。真tm愉快,我写了一晚上调了一上午(到三点)
很显然可以发现 \(i\) 能删掉的点一定是一段连续的区间(这里的删掉是指i,i+1,...i+p+1可以被删的只剩 \(i\)),这个我们可以 \(O(n)\) 递推出来。
用 \(f[i]\) 表示 \(i\) 能删到哪里,那我的转移就是看 \(i\) 能不能删掉 \(i+1\),如果行想话,\(ans\) 跳到 \(f[i+1]+1\),再判断,直到删不掉为止。
容易发现对于一个 \(i\) 它只会被最近的能删掉它的点遍历,所以是 \(O(n)\)。
然后就是可以发现对于每个 \(i\),它能转移的区间就是 \([i+1,f[i]+1]\),一看就非常线段树,所以直接做就是 \(65pts\),也就是我的赛场得分。
由于线段树是没有前途的,于是我们考虑单调栈,然后就变成了 \(O(n^2)\),有一个 \(n\) 是比较字符串的复杂度。
感觉很有前途,我们可以平衡树优化,变成 \(O(n\log^2 n)\),但是感觉过不去。
由于平衡树没有前途,所以我们考虑一只 \(\log\) 的做法。
发现一个性质,这里面出现过的每一个字符串,要么是原串的一个后缀,要么是一个出现过的串的前面再添一个字母。然后我们可以发现,这个形式非常倍增+hash,于是就过了。
用 \(f,g\) 分别记录 \(i\) 跳 \(2^j\) 步的字符串对应的位置和哈希值,然后直接倍增比较即可。