排版可能有点乱,懒得修了。
每天最开始的T1,T2,T3是模拟赛题目。
Day1
只会打爆力,爬了爬了
T1
-
有一个数列 (a[n]) 满足:
-
(a[0]=a)
-
(a[i]=a[i-1]+f(i)*a[(i+b)/c])
-
其中f(i)是一个关于i的m次多项式
-
求 (a[n])
-
(nleq 10^{18},mleq20)
懒得记柿子推导过程了()
记 (p_i=frac{i+b}{c})
一般地,求 (sum_{i=1}^n g(i)a_{p_i}),其中 (g(i)) 是关于 (i) 的 (k) 次多项式。
最后结果是 (a imes sg(n)+sum_{j=1}^{p_n}f(j)(sg(n)-sg(q_j))a_{p_j})
(q_j) 是最后一个 (p_x=j) 的数。
其中 (f(j)(sg(n)-sg(q_j))) 是关于 (j) 的 ((k+m+1)) 次多项式。
从 (g(x)) 求 (sg(x)) 直接拉插,复杂度 (mathcal{O}(k^2)) 的。
总复杂度是 (mathcal{O}(m^2log n))(?)
咋2021年了还网络流。
分成的三个问题是等价的,对于其中一个问题单独考虑。假设现在考虑的是颜色1,假设只有颜色2被干掉了,那么颜色1的点会形成若干个连通块,设这个答案为 (a);同理颜色3也会使颜色1形成若干个连通块,设这个答案为 (b)。
可能有最完蛋的情况是两个连通块都需要一个特殊点,共 ((a+b)) 个。考虑哪两个连通块可以共用一个点,这是个匹配问题,想到网路流二分图最大匹配。
一个点如果同时存在 (a) 中的连通块和 (b) 中的连通块,那么这个点就可以使这俩连通块共用一个特殊点即这个点。
给每个连通块建个虚点,一个同时在两个连通块的点就把这两个连通块连起来,那么这个二分图每一个匹配就会减少 (1) 的答案。
跑二分图最大匹配即可。
(mathcal{O}(nsqrt n))
T3
算法一:基于长链剖分,问出最深点 (x) 和其他所有点和这个 (x) 的距离,则可知根到 (x) 的点为哪些以及其他点在哪个子树里,再递归下去处理,复杂度 (mathcal{O}(n^{1.5}))。
算法二:不会
非传统题
提答,交互,通信。
提答
退火
典型应用:
- TSP问题,直接对答案排列退火,每次交换两个位置
- 多个背包的背包问题:每个物品指定一个背包或者不放,能放则放,对指定的背包退火
- 最大独立集,随机排列,依次选哪些点。
CTSC2018组合数问题
对每个问题安排在哪台机器上进行退火,每次改变一个任务被安排的机器。
CTS2019 无处安放
可能是对放入矩形的顺序退火,每次放的时候尽可能往左下角堆,可以形式化成对每个位置求个估价函数。
具体地,可以枚举大矩形的长,退火目标为最小化宽。
找规律
猜想出题人可能会造什么样的特殊数据,再写个程序验证一下。
造计算机
给一种计算节点的模型(存储的数据类型以及支持的运算),搭建一个计算的体系来完成相应的计算任务。
思路:
-
看给的计算节点是什么,运算是什么,有哪些特性(比如多了哪些不常见的,少了哪些常见的运算)可以利用。
-
求解目标,把求解目标尽可能拆分成基本运算。
-
确定给定的运算哪些需要,哪些是凑数的。
-
如果拆出来的基本运算没有给定,利用已知运算的性质凑出来。
-
找各个测试点前后的关联。
For example~
NOI2016旷野大计算
比方说实现取符号,可以直接扩大权值然后求 (s(x))。
反正就是构造构造构造。
交互
询问次数要求 (100) 次以下的,一般是一些奇妙的二分?或者卡次数,分类讨论。
询问次数 (mathcal{O}(n)) 的,可能是从暴力的 (mathcal{O}(n^2),mathcal{O}(nlog n)) 算法优化下来的。
询问次数更多,可能卡算法,更像是传统题(WC2018即时战略)
栗题
有两个 int
范围内的正整数 (x,y),每次可以询问两个数 (z,w),交互库返回 ((xoplus z)) 与 ((yoplus w)) 的大小关系(大于/等于/小于),要求出 (x) 和 (y) 分别是多少,询问次数 (65) 次。
从高到低每次问 (1,0) 和 (0,1),根据结果讨论出这一位是 (0) 还是 (1),去掉这一位之后剩下是 (x) 大还是 (y) 大。
栗题二
二分猜数题,有 (m) 次询问,总询问次数上界很紧,为 (m(log_2(n+1)+0.1))。交互库会根据询问策略动态调整下一次询问的数。
假如把决策树建出来,会有一些深度深 (1) 的叶子和浅的叶子,你的目的是不要让交互库去问那些深度较深的叶子。
直接从上到下问是很完蛋的,因为交互库特别神仙,即使你写了个随机也冲不过去。
考虑直接钦定哪些点是会GG的点,然后向上合并决策。为了保证均匀仍有些细节。
栗题三
有 (n) 个机器,好机器说真话,坏机器真假无法预料。好机器比坏机器多。在不超过 (2n) 询问内判断每个机器好坏。每次询问是让两个机器互相检测对方是否是好机器。
维护一个集合,要么全是好的机器,要么全是坏的机器。每次新机器和栈顶询问,如果都说对方是好机器则扔进栈,否则把栈顶弹掉和新机器一起丢掉。
剩下的一定是好机器,拿一个来询问全局。
栗题四
竞赛图,每次询问一条边的方向,找到一条点数为 (n) 的链,(nleq 10^3) 询问次数 (leq 10^4)。
考虑归纳,对于 (n=1),显然。
每次加入一个更大的 (n),如果链首指向 (n) 或者 (n) 指向链尾,那么连上就ok了。如果不行呢?假设指向 (n) 的是 (0) 边,起点为 (n) 指向链的是 (1) 边,以靠近链尾为前,以靠近链首为后,那么我们的目标是找到两个相邻的点,前面一个 (0) ,后面一个 (1),然后把这两个点断开,接上 (n)。
所以这个东西就可以二分了,首先二分中间位置,如果是 (0) 的话,递归右半边询问,否则递归左半边询问,是个子问题,最终一定能锁定一个位置有前后相邻的 (0,1)。
栗题五
二叉查找树,键值是点的编号,每次询问 (u,v) 返回 (u) 是不是 (v) 的祖先。
用 (2n) 次询问建出整棵树。
模拟建一棵笛卡尔树。
通信
一般来说写两个程序,首先执行程序A得到一些输出,这些输出经过处理之后输入到程序B,要求程序B完成一些任务。程序A和B之间一般不能通过其他方式交流。
栗题一
A输入一个无标号有根孩子间有顺序树,输出一个128位01串,B得到这个01串,还原树。
可以把树转换成 (2n-2) 的括号序列,个数是卡特兰数 (C_{69}) 刚好比 (2^{128}) 小一点。则变为求字典序第 (k) 小的括号序列,给定括号序列求字典序第几小。
栗题二
A输入一个 (10{18}) 以内的非负整数,输出一棵不超过 (100) 个节点的无标号树,B输入这棵树,输出A输入的树。
基本思路是拉出来一条链,然后在一个点上挂若干点来表示信息。
算法一:用几个节点在链头和链尾做标记来表示头尾,链长 (30),一个点上挂 (0,1,1+1,2) 来表示 (4) 个不同的四进制位。
栗题二
A输入一个 (nleq 1000) 个点的有标号图,输出一个 (n+12) 个点的无标号简单图,B输入这个无标号图,还原出原先的有标号图。
看懂了没来得及记。
栗题三
A和B各输入一个 (1sim n) 元素的子集....
构造个排列,自己有的数不动,剩下的循环位移一位。
如果两个手里有公共元素,那么复合出来肯定不止一个轮换。
可以证明如果两人手里没有公共元素且两人都没有的数有奇数个,复合起来一定只有一个轮换。
A告诉B自己手里有没有 (1),以及元素奇偶性,程序B根据这个信息决定是否干掉 (1),从而使得判断等价于问轮换。
栗题四 IOI2020网络节点
奇数层点入栈时赋予一个新标号,偶数层点出栈的时候赋予一个新标号。
判断略,画下图就知道了。
Day2
T1
如果只有第一种限制,方案数是 (a_i-i+1) 乘起来。
算法一:容斥,dp
先把第二类限制容斥成 ((leq n) -(leq |a_i|-1))。
现在先将第二类物品的 (a_igets |a_i|-1)。
那么对容斥系数后面的一坨来dp,做类似于背包的东西。
先拉到一块儿排个序,设 (f_{i,j}) 为前 (i) 个限制只考虑 (j) 个 (leq a_i) 的限制的方案数,带容斥系数。
如果是第一类物品,强制选择这个限制,则为 (f_{i-1,j}cdot (a_i-j+1) o f_{i,j+1});
对于第二类物品,既可以选择这个限制,也可以不选。
选择:(f_{i-1,j}cdot (-1)cdot (a_i-j+1) o f_{i,j+1});
不选:(f_{i-1,j} o f_{i,j})。
注意到“不选”实际上是把 (leq a_i) 的限制变成了 (leq n),直接把它们留到最后统计的时候乘个阶乘就可以了。
T2
求出树上距离为 (i) 的点对为多少对,点分治,上FFT。
算期望收益多点求值。
T3
全是 (0) 可以每两位一压,有 (0) 就设成全 (0) 废掉,否则表示信息。
正解:
两个程序用一个种子生成 (m) 个 (n) 位 (01) 串。后面线性基?完全忘了
构造
栗题一
构造一个长为 (2^n) 的 (01) 串,使得所有的相邻 (n) 位恰好组成 (2^n) 种不同的 (n) 位 (01) 串。
把所有 (n-1) 位 (01) 串看作点,每次从后面接一个 (0,1) 连出去边,跑欧拉回路。
栗题二
IMO2010
(6) 个盒子,初始每个盒子里面都有 (1) 个硬币,有两个操作:
选择一个非空的盒子,取出一枚硬币,后一个盒子放两枚硬币;
选择一个非空的盒子,取出一枚硬币,交换后面两个盒子里面硬币的数量。
要求进行若干次操作之后前 (5) 个盒子都空了且最后一个盒子有 (n) 个硬币。
原题 (n=2010^{2010^{2010}}) OI题的话可以看作 (nleq 10^5)。
首先先用基础操作构造出几个看起来非常有用的操作:
可以把 ((x,0) o (0,2x)) 视作 (P_1),把 ((x,0,0) o (0,2^x,0)) 的操作视作 (P_2) (((x,0,0) o (x-1,2,0) o(x-1,0,4) o (x-2,4,0)cdots))。
通过用 (P_2) 构造出的 (P_3):((x,0,0) o(0,2^{2^{2^{2^2...}}}(共x个2)),0)) 。((x,0,0) o(x-1,2,0) o (x-1,0,2^2) o (x-2,2^2,0) o (x-2,0,2^{2^2}) o...) 增长特别快,只要随便构造一个 ((0,0,k,0,0,0)) 出来,((k) 到 (6) 足够),调用 (P_3) 得到 ((0,0,0,2^{2^{2^{2^2...}}},0,0)) 再不断地给后面两个调位来浪费,直到变成 ((0,0,0,n/4,0,0)),调用两次 (P_1) 得到目标状态,如果 (n) 不是 (4) 的倍数分类讨论一下即可。
栗题三
IMO2020
(4n) 个小球编号为 (1sim 4n),每种小球各有一种颜色,一共有 (n) 种颜色,每种颜色的球各 (4) 个。把小球平分成两堆,要求每堆中每种颜色的球恰好有 (2) 个,而且两堆球的编号之和相等。
把第 (i) 个球和倒数第 (i) 个球捆绑在一起,能保证编号之和能满足,要满足每种颜色球各选 (2) 个限制。
把每种颜色建一个点,对于每一对绑定起来的球,连两条对应两个球颜色点的边,每个点度数是 (4),跑欧拉回路。给回路是上的边交替黑白颜色,染成相同颜色的边对应的球放在一组。每个点的每种颜色出边数量恰好为 (2)。
复杂度平衡
(O(sqrt n)) 区间修改,(O(1)) 单点查询,直接分块。
(O(1)) 单点修改,(O(sqrt n)) 区间查询,直接分块。
排序网络
比较偏工业方向的?)
(mathcal{O}(nlog^2 n)) 的奇偶归并排序:设 (n) 是 (2) 的次幂,先递归左右两半可以并行起来,合并两个序列的时候两侧拆出奇数位和偶数位,奇数位和偶数位分别合并成两个序列,再把第 (i) 个偶数和第 (i+1) 个奇数比较一下,可以一次并行完成。
栗题 IOI2021D2T3位移寄存器
就当是个造计算机题来做
假装是旷野大计算的模式:
orz qyc, 首先实现取绝对值,输出 (a+b+|a-b|/2) 和 (a=b-|a-b|/2) 即可。
现在要把一个 (x) 取绝对值,由于是补码存,可以让 (x) 右移若干位取得符号位,再将原数符号位置成 (0) 然后减去右移得到的符号位,即可完成取绝对值。
现在要并行计算,考虑奇偶归并排序的网络,用位运算解决把要比较的取出来,合在一起并行计算,然后再放回去。
IOI2021栗题选讲
栗题一 2021D1T1 分糖果
没听懂。
To be continued
栗题二 2021D1T2 钥匙
无向边换成有向边,每个点连向这个点钥匙能打开的边。
之后跑类似 Tarjan 的东西,形成了若干个有向内向森林,把根挑出来指向的点和自己连通起来,如果可以缩成一个点,则它们的钥匙共享了,意味着出边会增多。
给每个点集绑定它所携带的钥匙和出边,每次缩点的时候两部分互相查询来添加出边,询问的时候启发式询问,然后启发式合并即可。时间复杂度是一个log的。
栗题三 2021D2T2 地牢游戏
首先如果一直输大蛋,走的路程形成了内向基环森林。
如果要求出他第一次打胜仗是在什么时候?对于每棵内向基环树,就是查询他到根的链上是否存在 (w+val_xgeq a_i+val_i) 的点,其中 (val_x) 是根到 (x) 的路径权值和。
树剖之后对于每个重链开个线段树记录区间最小值,同时记录重链到这个点的前缀的最大值,这样只需要不断跳链然后查一次线段树。跳到环上之后只需要查一下环上的线段树就可以。
然后用类似21年SD省队互测dsq的T1一样,每 ([2^i,2^{i+1})) 分一个块,每次规定他只能打这个块里的怪,不在这个块里的怪视作超级无敌强。这样只需要求 (log) 次第一次赢在哪里即可。
栗题四 2018D1T3 werewolf
给定一个无向简单连通图,(k) 次询问 (u,v,l,r),询问是否有一条 (u) 到 (v) 的简单路径满足:
路径上有一个分界点 (x) ,前一半经过的点(包括 (u) 和 (x) )编号都 (geq l),后一半经过的点(包括 (v) 和 (x))都 (leq r)。
一棵重构树点的编号小于它的子树,一棵反之。
(u) 在其中一棵树上倍增跳到最浅的满足上述限制的点,然后询问变成了确定两个子树有没有公共点,变为二维数点问题,两个 dfs 序截成的一个二维矩形数点。
栗题四 2018D2T1 doll
构造一张图,题意略。
先假设 (n) 是 (2) 的幂 (-1)。构造一个类似线段树的二叉树结构。但是有很多节点会浪费,如图二,先开掉一条链,像二进制拆分一样把 ((n+1)) 拆分成不同二次幂,再根据这些二次幂决定使用哪些子树。
栗题五 2018D2T2 highway
先把所有点都标记为 (a) 求 (s) 到 (t) 的最短路。
每次二分一个 (mid),将 (1sim mid) 点的邻边都改成 (b),找到一个分界点,使得这个分界点 (x) 使得 (1sim x-1) 不变,(1sim x) 最短路就变了。
得到 (s o t) 上的点 (x) 之后,从 (x) 出发 bfs,将 bfs 到的点按距离从大到小排序,二分一个前缀改成把它们的邻边改成 (b),找到一个位置,从这个位置开始最短路改变了,则这个点就是 (s),同理从 (s) 开始 bfs 二分到的点即为 (t)。
分析这个做法,非常的完蛋,询问次数会被毒瘤的出题人卡到了 (52) 次且无法优化。
一开始二分的点变成二分边,这样能找到一条边在 (s) 到 (t) 的路径上,假设为 (u,v),(u) 离 (s) 更近,(v) 离 (t) 更近,则可以划分出两个点集 (S,T),分别为离 (u) 更近的点和离 (v) 更近的点,再像上个做法一样二分,分析下来次数正好卡进去。
Day3
T1
lxl: 提醒大家写快读。
懒得记了。
T2
一看上去很模拟费用流。
先建立一个二分图,然后模拟费用流。
曹队说打了个表看出来是只会走一次反向边。
设一个空位两侧的较大值为 (d),较小值为 (c)。
现在二分图左侧有 ((n-1)) 个点代表空位,右侧 (m) 个点代表要插入的数,有两类转移:
-
不走反向边,只有两种转移,右侧最大的 (a_i) 和左侧最小的 (d) 匹配,右侧最小的 (a) 和左侧最大的 (c) 匹配,开个堆维护。
-
走反向边,有四种转移,第一次从右侧走到左侧的开销有两种,和第二次从右侧到左侧的开销也有两种,也是类似地用堆维护。
T3
离线:先把询问记下来,扫描线扫进来单点修改,扫出去单点修改,查询是一个区间查询。
按三的倍数分散层叠(?)
完全不懂这些科技啊!!!
CF数据结构题
CF150E
给一棵带边权树,求一条边数在 ([L,R]) 之间的路径,并使得路径上边权的中位数最大,输出可行路径的两个端点。要求一个log复杂度。
二分答案,变成点权 (1) 和 (-1) 的树,求是否有长度 ([L,R]) 的路径点权和 (>0)。
长链剖分之后,短链每次合并进来的时候查询一个以深度为下标的区间上最大的前缀和,按 (log n) 分一个块,用一个动态 ST 表,前面预留出一个散块和一个整块,当修改到整块的时候意味着我们同时可以进行一个 (log n) 的操作,问题解决。
CF793F
蜗牛在树上爬,两种移动方式,沿着绳子向上爬,或者顺着树干往下溜。
高度为 (n) 有 (m) 条绳子,链接 (l_i,r_i),保证 (r_i) 两两不同,(q) 次询问蜗牛从 (L) 开始爬,只考虑 ([L,R]) 之内的绳子,蜗牛最高能爬到的深度。(n,m,qleq 10^5)。
询问有两个自由度,有四种扫描线方法,扫 (L/R) 从小到大/从大到小。
想了一下 (R) 从小到大扫,每次加绳子,比较好做。
数据结构维护每个位置 (x) 到 (y) 的答案 (f_x),从 (y) 到 (y+1) 的时候,他增加的绳子一定是 (r_i=y+1)。
也就是数据结构维护支持单点插入 ((f_{y+1})),和全局 (f_x) 大于等于 (l) 且 (xleq l) 的 (f_x) 改为 (y+1),且这个 (y+1) 是全局最大值。可以直接吉司机线段树做到一个 (log),lxl 讲的线段树是每个节点维护一个单调的栈,每次把一个上缀弹出之后push进去一个最大值。
CF536E
不懂。
CF1476G
带修莫队,不同出现次数只有根号种,拿出来 (>0) 的出现次数排序后,答案为最短的连续一段其和 (geq k),双指针扫。复杂度懒得算反正挺对(?)
CF1019E
有一棵 (n) 个点的树,每条边边权是一个一次函数 (a_i imes t+b_i),求对于所有的 (tin [0,m-1]) 的树的直径。(nleq 10^5,mleq 10^6,a_ileq 10^5,b_ileq 10^9)。
听得半懂不懂。看来我就是神。
CF1109F
考虑扫描线,对于每个右端点用LCT维护区间不含有环的最小左端点。
注意到 点数-边数=1则为树,否则为森林。
右端点移动的时候每个点到右端点的点数 (+1),新增的点与相邻的点如果有边则有一个区间 (-1),写个数据结构支持区间 (-1),维护区间 (0) 的个数。
CF1446F
二分答案,变成给定一个圆,有多少点对的连线完全在圆外。
一个点和圆的两个切点对着这个点的一段圆弧,如果两个点对应的圆弧有交点则连线在圆外。
转化成给定一个环,有 (n) 个区间,求有多少个区间两两有交,二维数点就行了。
CF1172F
问题转化成一个初值在 ([l,r]) 中被减去了 (p)。
记 (f(x,l,r)) 为经过 ([l,r]) 后减去 (x) 次 (p) 最小的初始值。
可以发现 (f(x+1,l,r)geq f(x,l,r))。
(f(x,l,mid),f(y,mid+1,r)) 能合并出 (f(x+y,l,r)) 需要满足:
- (f(x+1,l,mid)geq f(x,l,mid)) 保证左区间会被减去 (x) 次。
- (f(x+1,l,mid)-xcdot p+sum(l,mid)geq f(y,mid+1,r)) 保证到了右区间足够可以减去 (y) 次。
后面lxl讲不下去俺也听不懂了。
lxl:这一点也不数据结构啊,换题,PPT上写的肯定是对的。
CF1039E
对于每个 (x) 处理最右能跳到哪里,跨越长度 (leq sqrt n) 的用 LCT 维护,(>sqrt n) 的暴力跳。
CF1491H
像弹飞绵羊一样分块,维护每个点跳出所在块第一次跳到哪个点。
询问的时候把 (x,y) 跳到的 (sqrt n) 个点取出来,看在哪个块第一次相遇,那么LCA一定在这个位置的后面,暴力即可。
发现一个块最多被减去根号次,少于根号直接重构,大于根号时 (nxt_i=fa_i) 直接打标记解决。
CF696E
直接重链剖分,对于每条链用一个线段树维护区间最大值,一个点要是有多个物品的话可以在叶子开个堆维护。
每次询问的时候把路径上经过这 (mathcal{O}(log n)) 个链的最大值拉出来放到个堆里面,每次的时候弹出堆顶,然后在对应的线段树上修改。复杂度 (mathcal{O}(n log n))
Day4
T1
快乐斜率优化
T2
考虑树的情况,挑个最大叶子让它当根然后从下到上染色。
快乐啥也没听见。
T3
相当于维护动态树链剖分。
一次加点发生重边切换的次数仅有 (log) 个。
LCT 维护:对于每个轻儿子,其父节点的重儿子子树被减了多少次才会产生重儿子的切换。
复杂度两个 (log)
CF1515H
按位异或的话就Trie上打个标记即可。
按位与和按位或会合并节点,均摊复杂度是对的。如果与和或已经合并过了或者说根本没有另一个儿子,再进行与和或可以直接看做异或打标记。
CF1148H
扫描线从左往右扫序列维。
固定右端点,mex是不降的,也就是一段段区间。
后面没听懂。
根号数据结构
整数矩阵乘法:值在 ([0,2^w)) 的整数。
(01) 矩阵乘法:值为 ([0,1]) 的整数。
Bool matrix mul:(ans_{i,j} = | {a_{i,k}&a_{k,j}})。
(x<A) 加 (y<B) 和
二维平面 (n) 个点,每次操作为所有 (x<A) 的点加,查询 (y<B) 的点和。
用区间逆序对规约这个问题。
把区间逆序对看成一维扫描线扫右端点记录左端点的答案。
那么插入一个数相当于 (y<a_r) 的点 (+1),查询一个左端点相当于查询 (x>=l) 的点和。
所以可以规约成 (x<A) 加 查询 (y<B) 和、
行加列和
单点加查一圈和
给一个图,每次将 (x) 加,查距离 (x) 不超过 (1) 的节点的和。
将值存在边上,建立图的邻接矩阵,就变成行加列和问题。
具体地,设邻接矩阵为 (f_{i,j}),一个点加即 (f_{x,v}) 加,查即 (f_{v,x}) 和,其中 (v) 为与 (x) 有边的点。
区间加区间rank
[Ynoi2010]D1T2
不弱于小Z的袜子,排除polylog做法。
把序列分块,用一个根号乘根号的矩阵维护块与块的贡献,(a_{i,j}) 为 (i) 块和 (j) 块的贡献。
后面没听懂
洛谷P7709
有一个序列 (a) 和操作序列 (b),三种操作:
- (a) 区间推平为一个数;
- 交换两个位置的数;
- 查询 (a_x) 的值。
每次令 (a) 初始为 (0),保留 (b) 的一个区间,依次处理 (b) 中的每个操作,求所有保留的 (3) 操作的和。
考虑扫描线扫操作维的左端点,维护右端点对应答案。
如果加进来一个区间染色,就会让一些没有确定颜色的位置确定下颜色。
看成一个二维平面,横轴为操作维,竖轴为序列维,若干查询相当于若干个点。扫到一个区间染色相当于对于一个后缀的竖轴区间的所有点挑出来处理掉。
用线段树,叶子上放个vector维护在哪些时间点被询问且没有被赋值,区间染色就会让某些位置上的vector后缀挑出来弹掉,交换相当于交换两个vector,均摊复杂度是对的。
[Ynoi2008] rplexq
一棵树,每次查询给出 (l,r,x),对于每个 (lleq i,jleq r,lca(i,j)=x) 的方案数
答案为 (x) 里面有多少对点减去所有儿子子树里面有多少对点。
对点的度数根号分治。
后面很麻烦,看看这个吧
https://www.luogu.com.cn/blog/newbiewzs/p6782-ynoi2008-rplexq-ti-xie
[Ynoi2008] rrusq
啥玩意啊
晚上讲座
Day5
字符串
上午蹭隔壁的课针不戳
KMP
性质:
- border 的 border 也是自己的 border。
- A 和 B 都是 S 的 border,要不然 A 是 S 的 border,要不然 B 是 S 的 border。也就是一个串的 border 互为 border。
所以求出字符串 (S) 的border就不断跳border即可。
对于字符串 (s) 的前缀 (S_i),注意到 (S_i) 的 border 减去 (s_i) 一定是 (S_{i-1}) 的 border。
求出 (S_i) 的最长 border 就不断跳 (S_{i-1}) 的 border 即可。
这个算法正确性的一个保证是:设最长 border 长度为 (l),则 (l(S_{i+1})leq l(S_i)+1)。
先自己匹配自己,再两个串匹配就变成了 KMP 算法。
性质:每个 border 和一个周期对应。
Eg3 洛谷P3193
给一个数字串 (T),求有多少长度为 (n) 的字符串 (S) ,使得 (T) 不在 (S) 中出现过。
(|T|leq 20,nleq 10^9)
设 (f_{i,j}) 为考虑 (n) 的前 (i) 个字符,有最大的 (j) 使得后 (j) 个和 (T) 的前 (j) 个相同。通过预处理 (T) 的 border 可以列出来 (f) 的转移,注意到可以列成一个 (|T| imes|T|) 的矩阵,直接矩阵乘法优化递推即可。
时间复杂度 (mathcal{O}(|T|^3log n))。
Eg4
01 串 (T),按照以下方式生成字符串 (S),每次可以在 (S) 的右边概率随机添加一个 (0,1),概率为 (p) 和 ((1-p))。
(|T|leq 10^6)
设 (E(i)) 为 (S) 极大后缀和 (T) 前缀相同的长度。
有 (E(i)=p(E(i+1)+1)+(1-p)(E(i')+1))。
其中 (i') 为类似 KMP 匹配得到的匹配成功的位置。
高消很完蛋,考虑用类似这道题的处理方式,得到 (E(n)) 关于 (E(0)) 的一元一次方程,求解即可。
SA
(mathcal{O}(nlog n)) 对 (S) 的所有后缀排序。
原理和基数排序一致,不多赘述。
设 (sa_i) 表示排第 (i) 位的后缀(根据起点下标分),(rk_i) 为起点为 (i) 的后缀的排名。
设 (h_i=LCP(sa_i,sa_{i-1}))
则 (LCP(i,j)=min_{rk_ileq kleq rk_j}{h_k}) 假设 (rk_ileq rk_j),正确性显然。就是RMQ。
不易证 (h_igeq h_{i-1}-1),暴力即可。
Eg2
询问一个字符串有多少本质不同子串。
Eg2+
询问一个字符串的第 (k) 小子串。
和上个差不多,预处理出算 (ans) 时的前缀和然后二分即可。
Eg3
给两个串,求其最长公共子串长度。
假设为 (s_1,s_2),先用一个不在字符集中的字符'#'链接起来 (s_1,s_2),即为 (s_1+#+s_2)。
求这个字符串的 (h),有的后缀来自 (s_1),有的来自 (s_2),需要找到一个来自 (s_1) 的后缀和一个 (s_2) 的后缀使得他们之间 (h) 的最小值最大,显然判排名相邻的即可。
Eg8
给若干个串,求最长公共子串长度。
Sol1:拼在一起后缀排序,二分答案,把大于等于答案的 (h) 划分成一个块,看所有块中是否来自了所有串即可。
Sol2:不二分答案,直接双指针即可。
Eg7
给定字符串 (S),多次询问 (S_{[a,b]}) 的所有子串和 (S_{[c,d]}) 的 LCP 最大值。
(d) 显然无所谓。求下SA,先定位出 (c) 所在的后缀。
二分一下答案,相当于在 ([a,b-ans+1]) 选出一个 (x),使得后缀 (x) 和后缀 (c) 的LCP (geq ans)。
现在知道了 (x) 的范围,再考虑 (LCPgeq ans) 的限制,也就是 (h_{rk_x}) 到 (h_{rk_c}) 的 (min) 要 (geq ans),那么这个限制可以化成一个 (rk_x) 的限制,其取值为 (rk_c) 左右的一段区间,因为 (rk_c) 向左/右的 (h) 的 (min) 是单调不升的。想要确定这个区间,可以向左向右分别二分一下。
这样是个二维数点问题,其编号为一维, (rk) 为一维,就是查询一个矩形里面是否有点。直接暴力做是 (mathcal{O}(nlog^3n))。
对于所有询问的每次二分答案拿下来一起扫描线,时间复杂度 (mathcal{O}(nlog^2n))。
Eg4
给一个串求最长的两个不相交且长度相等的子串 A 和 B,使得对应位置差相等。
差分一下变成求最长的相等不相交子串,二分答案,把 (h_igeq k) 的若干个块,看最靠左和最靠右的距离是不是 (k)。
优秀的拆分
只需要对每个后缀求有多少个前缀是 (AA) 的形式。再类似地统计每个前缀有多少个后缀是 (AA) 的形式然后方案数乘起来求个和即可。
现在考虑对每个后缀求有多少个前缀是 (AA) 的形式,先 SA 一下。
枚举 (A) 的长度 (L),现在每 (L) 给 (S) 分个段:
枚举第一个 (A) 的左端点所在的块的编号,用 SA 算出这个左端点的取值范围,用一个差分统计答案即可。
具体地:
查询第 (2) 个黑线处的后缀 和 第三个黑线处的后缀 的LCP即可知道右端点的上界,类似地求出左端点的下界,即可知道左端点的取值范围。
问题解决。
上午模拟赛
T1
ARC100F
不考虑彩色序列的限制,(a) 序列出现的总数(((n-m+1)k^{n-m}))减去其不在彩色序列中出现的方案数。
-
(a) 就是一个彩色序列,答案为 (0)。
-
(a) 两两不同:
设 (f_{i,j}) 为长度为 (i),最大的 (j) 使得末尾长度 (j) 个互不相同,(g) 同理,但 (a) 已经出现了。
(f,g) 的 dp 很好转移,其中 (f_{i,j}) 到 (g_{i,j}) 还有一个考虑每个元素本质相同,是乘上一个组合数的逆元的转移。
这样 (a) 两两不同很好做了。
- (a) 相同:求出极长的没有重复数的前后缀长度,和上一种情况采用类似的dp即可,最终枚举 (a) 开头的位置来计算答案。
T2
CF1361E
如果以一个点为根,dfs树中所有非树边都是返祖边,则这个点就是有趣的。
假设一个根节点是ok的,能求出每个点是否是ok的,这个细节有待补充。
如果要找到一个满足条件的点,直接随机这个点即可。
T3
CF1290F
先极角排序,然后要满足向上/左走的和等于向下/右走的和,并且 (leq m)。
设一个七维的dp
CF360E
首先贪心一手边权不是 (l) 就是 (r),因为如果存在一种合法方案就可以转化成那种方案。
先把所有都设成 (r),从 (s_1,s_2) 分别单源最短路,如果对于某条边 ((u,v)) 有 (dis(s_1,u)leq dis(s_2,u)),则把这条边减小不会使得答案更差,所以不断找到这样的边改成 (l) 即可。
正确性证明不证,麻烦。
CF772E
如果加入了前 (i) 个叶子,那么树即为前 (i) 个叶子构成的虚树,最后 (n) 个叶子构成的虚树即为答案。
确定下一个叶子的位置的话,每次用当前的重心 (p),记录 (p) 的父亲和两个儿子,两个儿子内部随意选两个叶子,用这两个叶子和新叶子询问,确定新叶子在哪个位置,再递归下去处理。询问次数是 (mathcal{O}(nlog n)) 的。
CF843E
CF1209H
CF1270I
先定义一个矩阵 (f_{x,y}=oplus a_{x-u_i,y-v_i}),可证 (a) 全为 (0) 当且仅当 (f) 全为 (0)。(1)
假设在 ((x,y)) 异或了 (p),则能表示成 ((x+u_i+u_j,y+v_i+v_j)) 的格子才会发生变化,而 (i eq j) 的时候会异或两次抵消,则一定只有 ((x+2u_i,y+2v_i)) 才会发生变化,只会影响到 "奇偶性相同"的格子,变成四个子问题。
(1) 证明:定义变换 (f) 为求一个矩阵 (a) 的对应的 (f),({f^{2^k}}_{x,y}=oplus a_{x-2^ku_i,y-2^kv_i}),注意到 (t) 为奇数,则 (f^{2^k}=a),又可证结合律,所以 (f^{2^k-1}=f^{-1})。
所以我们相当于求 (a) 的逆元,得到的操作矩阵。
复杂度 (mathcal{O}(kt4^k))。
CF1292F
CF1365G
相当于进行 (13) 次询问,对于每个 (i),需要能用询问凑出 (i) 以外所有数的集合。
二进制分组可以做到 (20) 次询问。
我超!这个 (n) 是 (1000) 为什么不是 (1024),有猫腻!
考虑对每个位置重新标号,用 (13) 位包含 (6) 个 (1) 的二进制数当作标号。(inom{13}{6}=1716>1000) 恰好可以表示出来。
这样对于每一位,询问这一位为 (0) 的二进制数的按位或值,输出的时候看这个数哪些位置是 (1),把这些位置为 (0) 的询问答案或起来即可得到答案,因为除这个数 (x) 以外的任何一个数 (y) 的标号一定至少存在一个位置,满足这个位置,(x) 的标号为 (1) 且 (y) 的标号为 (0),反证法易说明。
To be conitnued.
AGC028F2
假设数字都为 (1),分治,对于 (H*W) 的网格,令其上半部分为 (U),下半部分为 (L),现在要 (mathcal{O}(HW)) 统计 (U) 和 (L) 的数。
Day6
T1
长链剖分?
T2
T3
随机调整。
LOJ6357
先让编号都减去 1,(f(i,j)) 表示场上 (i) 个人,(j) 报 (1),(0) 的存活概率。
列出式子后发现每层 (i),状态可以连成环,环数为 (gcd(k,i)),可以单独对每个环进行高斯消元,但其实可以对每个环挑出来一个当主元,再"手动"解方程。
时间复杂度 (mathcal{O}(n^2))。
AGC016F
(n) 个点,(m) 条边的DAG,点按拓扑序编号。
在 (1,2) 号点放置一枚棋子,玩有向图游戏,不能操作者判负。求原 (DAG) 的 (2^M) 张生成子图有多少先手必胜。
总方案数 - 多少图中 (SG(1)=SG(2))。
将SG从小往大考很完蛋,考虑将SG从大往小,做dp。
比方说dp为 (f(S)) 为考虑点集合 (S) 内,有多少种方案使得 (SG(1)=SG(2)),通过枚举 (SG=0) 的子集来转移。
[NOI2013] 树的计数
[ICPC2018 WF]Gem Island
ZJOI2016 小星星
容斥 (T) 到一个子图 (S) 的映射数,设 (f_{u,v}) 代表考虑 (u) 的子树,(u) 映射到 (v) 上的方案数,即得做法。
CTS2019 氪金手游
容斥一下,答案变成 (不定向)-(外向)。
容斥dp一下。
栗题
将长度为 (2n) 的数组分为 (k) 段,每段长度都为偶数。
长度 (2n) 的随机排列,然后偶数位上升序排列,价值为每段中逆序对乘积的期望。
求所有划分的价值和,模素数 (5000leq Pleq 10^9+1)
(Tleq 10^4) 组询问,(kleq nleq 100)
不会。
300iq Contest 1 Expected Value
THUWC2019 令人印象深刻的题目名称
CF1208F
枚举 (i),从高位向低位贪心,维护一个 (ssubseteq a_j& a_k),构造 (s):若 (i) 这位是 (1),(s) 取 (0) 更优,(i) 这位是 (0),(s) 必须取 (1)。
问题变成快速检查是否存在一个 (ssubseteq a_j& a_k)。
qyc 说是直接做一个 fwt-and,可惜我不会,加入to do list。
有 (i<j<k) 的限制,提前 dp 一个 (f_x) 代表 (xsubseteq a_j& a_k) 的最远的两个下标。
Baltic OI 2013 Vim
CF1208G
Day7
T1
听sxw讲懂了,先咕咕咕。
听不懂T3,讲T3的时候来写T1解法了。
先考虑,如果把每个集合看成一个点,(A o B) 当且仅当 (max{A}>min{B}),则发现对于两个集合 (A,B) 要不然其中一个连向另一个,要不然既有 (A) 到 (B),又有 (B) 到 (A),这种方案合理当且仅当这个图存在哈密顿回路,由于是类似竞赛图的形式,等价于看这个竞赛图是否整个是一个强连通分量。
将每个数看成一个点,相邻的大的向小的连边,在同一个集合中的数,小的向集合中最大的连边,我们称这个边为返祖边。发现这个图为和上个图是等价的,看这个图是否为一个强连通分量,等价于除了最大数代表的点,其他的点的 (low<dfn)。
设计一个 dp,(f_{i,j,k}) 为从后往前考虑到了第 (i) 个点,划分了 (j) 个集合,最大的 (low=dfn) 的点是哪个(因为能走到这个点就可以将所有 (low=dfn) 的点变成 (low<dfn)),分类讨论一下 (i) 的返祖边连向了哪里来转移。
时间复杂度是三次方的。
其实和老师讲的最后一个做法是等价的,不过是另一个理解方式?
T2
直接带修莫队就冲过去了orzorzorz
bitset
做法待补。
T3
不会。
CF1208G
如果 (dmid m),则一定先选 (d) 再选 (m) 更优。假如 (m) 的所有因子都被选取了,加入 (m) 边形会带来 (varphi(m)) 条边。
因子 (1) 默认被选了,因子 (2) 被默认选取当且仅当存在偶数。由于任意奇数 (m,varphi(m)geq 2=varphi(4)),所以除了 (n=3) 外可以把 (m) 最大的换成正方形。
若 (dmid m,varphi(m)geqvarphi(d)),所以当 (ngeq 4) 时在 (varphi(1sim n)) 中选取最小的 ((k+2)) 个求和即为答案。
WF2019 Directing Rainfall (LOJ 6582)
先扫描线或者其他东西对板子排序,使得后面的板子只会被前面的板子落到。
维护一个 dp ,(f_i) 代表位置 (i) 落到地面需要的最少洞数,那么就是一个区间 (+1),区间从左到右或从右到左 (chkmin)。
后面的不大懂。
寻找车位 (CodePlus 2018 3月赛)
CF573E
可以证明贪心每次选择可以让答案增量最大的点是对的。具体咋证不会,cz_xuyixuan博客中有。
后面咋做不大会。