一句话题解3

目录


CF Deltix Round, Spring 2021 (open for everyone, rated, Div. 1 + Div. 2)

A:如果一次没有变化以后都不用做,一共最多变化\(n\)次,所以暴力做\(\min(n,m)\)轮即可。

B:发现可以两个两个分为一组搞,试一下就出来了。

C:我尝试了半天的做法:每次找到最后一个位置\(x\),满足\([x-a_x+1,x]\)\([1,a_x]\),然后把它作为\(x-a_x\)的子目录。题解做法:维护个栈,栈中记下每一层是第几个。如果遇到\(1\)就入栈,如果大于\(1\)就弹栈直到找到所存第几个是小于当前的。

D:随机一个人,有一半的概率他在解中被考虑到。然后取出与这个人有关的颜色,用FWT做一下即可。随机枚举大概50次。(PS:CF的time(0)是不变的,所以别人可以通过对着随机种子hack。为了防止被hack,可以利用评测机本身运行时间的波动性,借助clock()来增加随机种子的不稳定性,具体见这份代码

E:考虑要么加一个0,要么加(k-1)个0和1个1。第一个1前面的0长度需要枚举一下。列出式子稍微化简一下即可。

G:统计一下作为答案的区间的个数的总和,发现是\(O(n\lg n)\),只要能精准地找到作为答案的区间就好了。对于每个长度分别做。设\(qry(l,r)\)表示问某区间内的答案,找到最小的\(i\)满足\([L_i,R_i]\in [l,r]\),然后分成\(qry(l,L_i-1)\)\(qry(R_i+1,r)\)。用二维数据结构维护即可哇这是我第一次打二维数据结构诶。时间\(O(n\lg^3 n+m\lg^2 n)\)


7102. 【2021.6.3 NOI模拟】集合

从小到大排序,然后跑A*。每次取出平均值最小的,然后扩展(兄弟和儿子)。

因为每次扩展只会扩大,所以没有问题。


7103. 【2021.6.3 NOI模拟】匹配(口胡)

把匹配方案看成个排列,然后发现其实答案就是行列式,每个位置一开始是个一次多项式。

直接算是\(O(\frac{n^5}{\omega})\)的时间。另一种做法:找\(\frac{n}{B}\)个最高次为\(B\)的不可约多项式,在模每个不可约多项式意义下做高斯消元,最后中国剩余定理合并。预处理出值域(\(2^B\))内的所有值之间的乘法运算和求逆运算,于是就可以迅速地做高斯消元了。

(没有想细节)


7104. 【2021.6.3 NOI模拟】锻炼

如果没有颜色的限制,可以有这样的贪心:找到最小的右端点,在这个位置搞一次,顺便将其它经过这里的区间删掉。

正确性:这个右端点往左的位置,包含它的集合不会扩张。

现在有了颜色的限制。如果同颜色的区间的右端点不等,同样也可以类似地做,只是在当前位置放的时候,相同颜色的区间中,选择右端点最小的。

如果同颜色的区间的右端点相等,将左端点最大的区间右端点保持不变,其它区间右端点往左缩一格。调整直到同颜色区间的右端点不等,然后就可以用上面的方法做了。

模拟上述过程即可。时间\(O(n\lg n)\)


7107. 【2021.6.5 NOI模拟】超高校级的绝望

题目大意是假的

竞赛图缩点之后是一条链从前往后连边。预处理成每个块内部的贡献,然后\(O(3^n)\)子集卷积。

计算块内部贡献,可以DP钦定一条哈密顿回路,其它的边怎么优怎么连。时间\(O(2^n n^3)\)

(注意不存在大小为\(2\)的强联通分量……)


7106. 【2021.6.5 NOI模拟】杰尼罗斯 艾欧

一开始钦定点权为0,边权为1。定义价值为点权+邻边边权。现在考虑增量搞,考虑完\(1..i-1\),现在加入\(i\),要求不改变\(1..i-1\)的价值。设\(T\)表示\(1..i-1\)中和\(i\)相连的点的集合。

首先对\(T\)中点权为0的:把点权+1,边权-1。于是\(T\)中所有点点权为1。

现在对每个T中的点都可以做这样的操作:点权-1,边权+1,它价值不变,\(i\)价值加一。

由于\(T\)中至多有\(|T|\)种不同的价值,而经过这样的操作有\(|T|+1\)种取值,所以一定可以取到。

采取合适的实现可以做到\(O(n+m)\)


【UR #4】元旦三侠的游戏

\(b\ge 2\)的时候,状态是很少的,可以全部处理出来。

\(b=1\)的时候,处理出\(a\le \sqrt n\)的,后面的可以直接算出来。


【UR #4】元旦激光炮

假设三个数组长度为\(k\)(不够的补\(\infty\)),下标从1开始。

\(l=\lfloor\frac{k}{3}\rfloor\),然后比较\(a_l,b_l,c_l\)。然后取出最小的,不妨设是\(a_l\)。易证\(a_{1..l}\)都小于第\(k\)小。于是将它们扔掉,并\(k\leftarrow k-l\)。当\(k\le 2\)的时候直接暴力。次数大概是\(3\log_\frac{3}{2} k+6\)。可以通过。

题解中\(c_n=0\)的部分分也很有趣:考虑两个长度为\(k\)的数组求中位数,不妨设\(k\)为偶数,\(i=\lfloor\frac{k}{2}\rfloor,j=k-i\)。比较\(a_i,b_j\),如果\(a_i<b_j\),则对于\(a_{1..i}\)来说,\(a_{i+1..k}\)\(b_{j..k}\)大于它们,有\(n+1\)个数;对于\(b_{j+1..k}\)来说,\(a_{1..i}\)\(b_{1..j}\)小于它们,有\(n\)个数。于是将\(a_{1..i},b_{j+1..k}\)除去,中位数不会改变。于是每次砍半,次数\(2\lg k\)

(实际上在\(c_n=0\)时,根据\(kth=\min_x \max(a_x,b_{k-x})\)得,可以二分出最大的\(x\)满足\(a_x<b_{k-x}\),然后比一比\(b_{k-x}\)\(a_{x+1}\)即可)


【UR #4】追击圣诞老人(口胡)

求前\(k\)小肯定是A_star。普通的A_star实现是每次找到权值最小的状态,扩展它的第一个儿子和下一个兄弟。

我的想法:直接维护第几大。不用脑子的想法就建个根到节点的主席树,于是时间\(n\lg n\),空间\(3n\lg n\),不够;想了半天想了个括号序,左括号加入右括号删除,线段树维护,每个区间中分别维护加入和删除的数的有序序列(调整一下数的大小使其严格有序)。二分第几大是多少,然后在线段树上对应的区间上二分。空间\(2n\lg n\)也许可以,然而时间\(n\lg^2 n\)

题解:A_star并不一定严格只找下一个兄弟,可以限制出边的集合类似分治地去搞。用人话说:状态记\((w,x,Suc)\)表示权值为\(w\),当前在点\(x\),出边的集合为\(Suc\)

考虑将\(Suc\)变成\(Suc_l\bigcup Suc_r\bigcup y\)\((w+\dots,y,\dots),(w+\dots,\min Suc_l,Suc_l),(w+\dots,\min Suc_r,Suc_r)\)。暴力做法可以直接求出\(Suc\)(以指向堆的节点的指针的形式),用可持久化可并堆+倍增来搞。

实际上一条链\((u,v)\)上,可以找到其最值,将链分成两个部分,相当于搞了个堆。只需要记链的两端,就没有必要将堆处理出来。原来的集合拆成三条链即可。

用树剖实现可以做到空间\(O(n)\)时间\(O(n\lg n)\)


【UR #5】怎样提高智商

猜:全部都是A 0 0 0 0,答案为\(4*3^{n-1}\),感觉玩不出更大的,于是一交过了?


【UR #5】怎样更有力气

要每次对于一个链上的点集,以及一些边,用补图的边合并连通块。

首先把有边连接的点统计一下。如果存在没有边连着的点,那么在补图中它连着所有点,此时可以合并整个点集。

否则,显然\(m\ge \frac{n}{2}\),于是暴力将点集拉出来做不亏。用常规的补图生成森林的方法可以做到\(O(m)\)(比如选出一个度数最小的,它和没有边相连的直接合并,和它有边的点对于所有点暴力连边,因为最小度数不超过\(\frac{2m}{n}\),所以时间是\(O(\frac{2m}{n}n)\)的)。

第一种情况合并整个点集不能暴力。我的写法是另外维护个并查集,表示树上颜色相同的连通块。

时间\(O((n+m)\alpha)\)(如果不算求LCA的话)


【UR #5】怎样跑得更快

考虑方程组\(\sum_{j=1}^n f(\gcd(i,j))g(i)h(j)x_j=b_i\)

\(f(n)=\sum_{d|n} fr(d)\)。求出\(fr(d)\)。原式化为:\(\sum_{d|i} fr(d)\sum_j [d|j]h(j)x_j=b_i/g(i)\)。其中\(\sum_j [d|j]h(j)x_j\)记为\(s(d)\)

\(\sum_{d|i} fr(d)s(d)=b_i/g(i)\),可以解出\(fr(d)s(d)\),除以\(fr(d)\)得到\(s(d)\)(模意义下,如果\(fr(d)=0\),如果\(fr(d)s(d)\neq 0\)无解,否则\(s(d)\)可以任意钦定)。

根据\(s(d)\)的定义式又可以解出\(h(j)x_j\),进而得到\(x_j\)

全程用普通的狄利克雷除法操作即可。


【UR #6】智商锁

竟然是乱搞题……

随机1000个点数为12的图,记下其生成树个数\(f_i\)。然后找到\(f_Af_Bf_Cf_D\equiv k\pmod p\)。可以通过折半实现。

适当调参可以过……


【UR #7】水题生成器

猜了个做法过了。题解说那是“逆n阶乘表示”。

大概是,设\(a_i=n(n-1)(n-2)\dots i\),那么域内每个数都可以表示成\(\sum a_ib_i\)的样子,其中\(b_i<a_i-1\)

于是贪心地确定即可。


7120. 【2021.6.12 NOI模拟】多项式因式分解

如果先乘\(x\)的若干次方将最低项次数补为0,那么分解是唯一的。

首先求出这个分解。每次以0次项下一项的次数搞一搞即可。分解时间\(O(60n\lg n)\)

后面就是要做个背包,以凑出负数最低次数。

直接做背包,只存有值的位置。发现有值的位置其实不超过\(n\)。于是时间\(O(60n\lg n)\)


【2021.6.12 NOI模拟】树猜

常规的交互题。随机增量构造。当前维护一棵虚树以及它的链剖分(每个非叶子节点都有重儿子,重儿子钦定为子树中节点出现时间最小的儿子)。

加入某点\(u\)\(rt\)的子树中:

  1. 找到\(rt\)所在重链的最低点\(d\),令\(t=query(u,d)\),分类讨论:\(t=d\)\(u\)设为\(d\)重儿子结束),\(t\)没有出现过(二分找到\(t\)的位置,插入并将\(u\)作为其轻儿子),\(t\)出现过。
  2. 如果\(t\)出现过,令\(c=query(u,lightson(t))\),分类讨论:\(c=t\)\(u\)设为\(t\)轻儿子结束),\(c\)出现过(递归进入\(c\)子树中插入),\(c\)没有出现过:此时\(c\)一定是某个\(v\in lightson(t)\)\(u\)的祖先,二分出这个\(v\),搞一下结束。

分析下次数:每次二分之后必定伴随着一个点加入;每次经过一条轻边需要\(1\)次,期望\(O(\log)\)。(最坏情况是一条链,链上每个点挂着一个叶子。于是如果一个叶子能产生影响,它应该是父亲所在子树中除父亲外出现得最早的。于是贡献大概是\(\sum_{i=2}^n\frac{1}{i}\)这样的形式。)

于是总体\(O(n\lg n)\)


ARC122

A,B略

C:首先可以斐波拉契数列快速逼近\(n\)。然后可以看做:对于当前数列,从前往后,可以选择将当前位置加一,然后更新后面的数列。本质上相当于斐波拉契进制。

D:决定权在后手,后手心中所想的任意一个配对方案,他都可以做到。如果最高位为1的有偶数个,就分成两部分分开做;如果有奇数个,一定存在一对异或后最高位为\(1\)。于是最高位为0和1中的数分别找一个,使得其异或最小。用Trie搞搞即可。

E:显然当前集合的子集的答案比当前集合不会更难。每次找到一个能丢到最后面的数,如果能找到,剩下就是个子问题,不会更难;如果不能找到,一定无解。判定的时候算\(gcd(v,lcm(\dots))=lcm(gcd(v,\dots))\)


7125. 【2021.6.16 NOI模拟】装备

将题目给出的二元组看成有向边。于是基环内向树不能动,现在只考虑内向树。从高到低考虑,尝试贪心搞,如果换更优,就尝试将祖先都向上顶一格;如果不换更优,就将子树全部标记不能换。


7126. 【2021.6.16 NOI模拟】比赛

首先可以写个普通的DP:\(f_{i,l,r}\)表示\(i\)\([l,r]\)中胜出的概率。时间\(O(n^5)\)可以过n=150

发现\(f_{i,l,r}=f_{i,l,i}f_{i,i,r}\)。于是将其变成两个状态\(f_{l,r},g_{l,r}\)分别表示\(l\)\(r\)获胜的概率。然后是\(O(n^4)\)

将转移方程写出来,发现大概是三个区间拼在一起。可以搞个辅助DP先拼两个。于是时间\(O(n^3)\)


7124. 【2021.6.15NOI模拟】苯为

发现对于某条点数为\(l\)的路径,贡献为\(g_{l(A+1)}(k-1)^{(n-l)(A+1)}\),其中\(g_i\)表示长度为\(i\)的环染色的方案数。显然\(g\)可以写成矩阵乘法的形式。于是大概是要对\(T^l\)求和,其中\(T\)是某矩阵。随便搞即可。


7122. 【2021.6.15NOI模拟】西克

\(O(n\lg n)\)过不了2e6……

点分治,向上的可以O(1)搞,向下的因为我菜不会所以我递归到下一层继续做。于是时间\(O((n+q)\lg n)\)

题解大概是拆成\(x\to lca(x,y)\)\(lca(x,y)\to y\)。向上:先计算\(f_x\)表示最近的祖先满足\(b_x=a_{fa_x}\),连成森林,遍历森林,在栈上二分得到;向下:用个可撤销并查集,遇到某个点将\(a_x\)\(b_x\)合并在一起。有可能新开一个\(b_x\),然而同色的\(b_x\)在之前已经被合并,另外开一个,并且将其它独立的\(b_x\)和它合并。时间\(O(n+q\lg n)\)


2021 计蒜之道 精英组 决赛 Day1

A:略

C:把数字按顺序排成个环。对于每个位置,求出以它开头,能到达的最后是哪个。求出来之后倍增跳一下。需要维护一段区间的点在树上的直径。


2021 计蒜之道 精英组 决赛 Day2

A:算不合法的。不合法即某个大于总重一半,发现不会同时出现两个不合法所以不用进一步容斥。折半搜索算一算即可。

C:发现可以视作\(x\to x+popcount(x)\)。于是大概是要:找两者的LCA,然后往后跳几步。可以发现每次增量最多\(18*9\),不会很多,于是除了最后三位之外,前面一定是可以每次加不超过\(1\)的。记个\(f_{p,s,j}\)表示前面若干位和是\(p\),后面三位是\(s\),其中第\(4\)位到\(j-1\)位都是\(0\),要让第\(j\)位加一,的最少步数以及后面三位会变到哪里。然后詹增即可。注意跳的过程类似于树状数组,要从低位向高位扫一下,然后再扫回来。


LOJ 6764. 「THUPC 2021」鬼街

质因数最多有\(6\)个。假设阈值为\(k\)。当警报响起的时候,至少一个质因数处大于等于\(\frac{k}{6}\)

所以质因数设置这个小阈值。如果超过小阈值就看看是否已经超过阈值。次数为\(\log_{\frac{6}{5}}k\)

时间\(O(m\log_{\frac{6}{5}} V \lg m*6)\),非常卡。windows上57s,虚拟机上8s,LOJ上7s……


7128. 【2021.6.18 NOI模拟】双⾊球

生成函数显然是\(\frac{(1+x)^n}{1-x^{m-1}-x^m}[x^n]\)。虽然这看着很简单但其实不可做……

展开得\(\sum_i \binom{n+i}{mi}\)。令\(F(n,k)=\sum_i \binom{n+i}{mi}\),发现\(F(n,k)=F(n-1,k+1)+F(n-1,k)\),并且\(F(n,m)=F(n+1,0)\)。于是将其拍成一维,令\(f(nm+k)=F(n,k)\),于是\(f(n)=f(n-m)+f(n-m+1)\)。常系数齐次线性递推即可。

简单的做法:如果最终选择什么已经确定,那么就是个简单的递推,可以用矩阵\(A^k\)表示。然后考虑哪些被选,选就乘\(A\)否则乘\(1\)。于是要求\((A+1)^n\)。还是用常系数齐次线性递推搞搞。


7129. 【2021.6.18 NOI模拟】数学分析

一次\(x\)变成\(\phi(x)\)相当于对它的每个质因子取一个将其减一。每次减一一定会出现2的因子。于是每步都一定会有个\(2\)变成\(1\)(除了奇数的第一步)。于是只要求每个质数做这样的过程能产生多少个2即可。

然后生成函数卷一下。


7130. 【2021.6.18 NOI模拟】计算⼏何

根据pick定理,题目等价于求面积为\(1\)的三角形数。

用最小的矩形框柱三角形。分三种情况:三角形一个顶点在矩形顶点,两个顶点在矩形相邻顶点,两个顶点在矩形对角顶点。

根据范围分析得第一种情况面积大于1,第二种情况很好算。剩下第三种。

引理:当\(m\perp n\)时,方程\(ma-nb=1\),在\(a\in[0,n-1],b\in[1,m]\)内的解有且唯一。

配合这个引理进行一波证明。可得:长宽gcd为1时(除了长宽等于1),有一解;gcd为2时,有两解。

(证明的时候巧妙运用对称性可大大简化)

列出式子之后反演,然后杜教筛即可。


7131. 【2021.6.19 NOI模拟】binom

\(ln\)前缀和。打表打太少跑不过去,要打多点超过代码长度限制,就用字符串压了压……

发现'??-'等于'~',要小心。

实际上积分就好了。


7132. 【2021.6.19 NOI模拟】reward

直接凸优化DP就好了。


7133. 【2021.6.19 NOI模拟】tree

什么做法都有。\(O(n\lg^2 n)\)的就有一堆。

有个\(O(n\lg n)\)的没卵用的做法:先建虚树,然后边分治。

dyp提供了一个比较厉害的思路(应该是\(O(\lg^2n)\)的):假设要合并并计算两个数组的贡献(假设下标范围为\([1,L]\)\(i+j\le lim\)有贡献)。如果\(L+L\le lim\)就都有贡献,如果\(1+1>lim\)就没有贡献。否则分别拆成左右半边,两两配对递归下去做。不知道怎么卡


【UR #8】决战圆锥曲线

显然如果\(x_1\le x_2,y_1\le y_2\),则\((x_1,y_1)\)没用。如果某个点\((i,y_i)\)有用,那么\(y_i\)是后缀最大值。期望有\(O(\lg n)\)个。

线段树,区间维护最大值。询问的时候从右往左遍历线段树,如果右端点和区间最大值组成的答案能更新答案就递归下去。正确性:如果出现这个东西能更新答案,那么必然存在一个\(y_i\)的后缀最大值,它一定是候选点。

时间小常数\(O(n\lg^2 n)\)


7134. 【2021.6.21NOI模拟】旅行计划

建dfs树,把非树边的端点和出发点作为关键点拉出来建虚树,处理出出发点到虚树上每个点的最短时间。

然后找到虚树上每个点的管辖范围,具体一点就是每条边上能找到个分界点。然后统计一下即可。


7135. 【2021.6.21NOI模拟】搬砖

稍微分析可得答案求\(\gcd(h_i-h_1)\)。用数据结构随便维护即可。


7136. 【2021.6.21NOI模拟】寻觅

ls的做法:从后往前,如果当前位置未标记,将其染成颜色1并将其相邻(只保留前面的位置)的位置标记;如果标记就递归到下一层做。归纳易证这是对的。

题解神仙做法:首先可以用3个颜色搞出长度4。每3个分成一组,每组取出出现时间最早的做子问题。回来的时候,对于没有被染色的点,最坏情况下要做长度4的问题,搞一搞即可,颜色增加3。


7137. 【2021.6.22 NOI模拟】⼈赢的情书

首先由\(s_{p_i}\le s_{p_{i+1}}\)。然后确定一下是否不能取等:比较\(rk_{p_i+1}\)\(rk_{p_{i+1}+1}\)即可。

然后是个保序回归。\(<\)可以通过将后面的信息(\(s\)\(v\))-1变成$\le \(。回去看论文有个\)L_p\(均值的概念,在\)p=1$时是取区间中位数。所以如果用单调栈的做法,要用个数据结构(比如可合并线段树)维护中位数。

也可以写出个DP。这个DP显然是个凸函数,每次加个"V"形。可以用线段树区间修改+区间赋值维护差分数组,也可以:从最低点作为分界,向左和向右维护斜率增加的位置(即维护斜率的差分的差分)。在加"V"的时候,对于最低点所在的那边(假设是右边),在最低点处+2,最左边-1相当于将第一个斜率增加的点移到另一边。用对顶堆维护。这题中可以只用一个堆。


7139. 【2021.6.22 NOI模拟】重建计划

前半:关键点之间求最短路然后连成个新图,在这个新图上最小生成树。可以水到46分。

后半:维护个已经选的点集,每次随机一个不在点集内的关键点,拉出一条点集到关键点之间的最短路。初始点集选择一个关键点。维护最短路时从点集开始跑,点集新加入点的时候重新扩展。可以水到49分。


6249. 【NOI2019模拟2019.7.3】七星连珠

用个集合幂级数作为矩阵元素。算行列式。为了防止被消掉所以每个位置乘一个随机系数。

为了更快,跑k进制异或FWT将其化成点值。


【UR #9】App 管理器

依次考虑双向边\((u,v)\),如果存在\(v\)\(u\)的路径并且不经过边\((u,v)\),那么将其定向为\(u\to v\);否则相反。

因为有解,从\(v\)\(u\)和从\(u\)\(v\)必然有个满足。如果都满足,因为有解至少有个满足,此时可证另一个也满足。


【UR #10】汉诺塔

按值域分治,将左半段和右半段分开,递归做。


【UR #10】世界线

先考虑假设能做无限次query。问题是如何分组使得能够区分每个点。

有个想法就是排成个大小为\(\frac{k(k+1)}{2}\)的三角形(\(i=1..k,j=1..i,(i,j)\)有点),发现此时每行每列都有特征:行或列上的点的个数不相同。

如果有剩下的呢?钦定\((0,0),(1,0),\dots\)放点。可以发现:此时\((0,0)\)所在行是唯一的包含一个元素的行(特判\(n=\frac{k(k+1)}{2}+1\),此时把剩下的点孤立即可。根据其所在行列的点数为\(1\)即可区分)。可以查出\((0,0)\),然后将和它同一列的都查出来,并去掉它们在对应行中的影响。然后就跟没有剩下的一样了。

估计一下query的次数。考虑每次选一个点,暴力查其它点看看是否和它在同个块中,查出来之后删掉。发现最坏情况的总次数为\(2\sum_{i=0}^{k-1}n-\frac{i(i+1)}{2}\),算一下发现它在范围内。


【UR #12】密码锁

首先可以想到可以分成集合\(A,B,C\)\(B\)作为一个强联通分量,\(A\)\(B\)连边,\(B\)\(C\)连边,统计方案。

可以将\(A,B\)合并,因为是竞赛图所以一定有且仅有一个强联通分量没有出边,这就相当于计算它的贡献。记这个集合为\(S\)

首先算它贡献为\((\frac{1}{2})^{|S|(|S|-1)/2}\)。如果存在某条概率为\(p\)的特殊边从\(S\)连出去,就乘\(2p\)的贡献。

发现可以根据特殊边连出的弱联通分量来搞,记个DP状态表示有多少个点在\(|S|\)中,此时的贡献;然后将各个弱连通分量的贡献卷起来。对于单个弱连通分量,直接枚举每个点是否在\(S\)中,计算贡献即可。


7141. 【2021.6.24 NOI模拟】麻将

最长\(L=24\)。把长度为\(L\)的所有子串存到桶里,如果桶没有满就尝试将其\(L\)往下压,此时每个状态去掉开头或结尾得到下一个状态。时间\(O(n)\)然而究极卡


7142. 【2021.6.24 NOI模拟】德州扑克

进行一堆差分之后,转化成:线段\(AB\)(左下-右上走向)和\(P\)点为左下的无限长的矩形的问题。

\(AB\)被完全包含:二维偏序。

\(AB\)\(P\)点上方延伸的射线相交(右方的可以对称计算):扫描线,splay按照截距来维护线段。


7143. 【2021.6.24 NOI模拟】将棋

\(t>T\)的时候,可以\(O(n)\)计算。

\(t<T\)的时候,建出虚树并对其链剖分。链内的可以预处理出根到节点的贡献(最后需要减去每条链和总共的LCA到根路径之间的贡献),枚举两条链计算它们之间的贡献(如果是祖先后代关系要把LCA往上的一段去掉)。于是要算\(\sum t^2\)次,约等于\(nT\)

现在问题是怎么计算这个贡献。两段链之间的贡献可以拆成两段从根开始的路径之间的贡献。

可以树上莫队。平衡可得\(O(n^\frac{5}{3})\)

也可以进一步对颜色的出现次数分块。如果大于\(B\),可以暴力,用桶预处理;如果小于\(B\),暴力搞出所有对。后者离线下来。把询问挂在其中一个节点上,然后遍历树。走一条边的时候,枚举所有对,给对应的那边加一。查的时候就可以查另一边链的前缀和。平衡可得\(O(n\sqrt {n\lg n})\)


【UR #13】Yist

按照权值从小到大考虑。如果不删,选择的区间不能跨过它,分成子问题。如果删,先将它删掉不会更劣。

答案为:对于每个要删的点,向左向右找到第一个小于它并且不删的,这中间大于等于这个点的数的个数。取最小值。

因为取最小值,可以从大往小考虑,每次暴力往两边扩展,并将扩展过的点打上标记。以后如果扩展到了打过标记的点,因为一定不会更优,所以可以退掉。

时间\(O(n)\)


LOJ3523. 「IOI2021」分糖果

因为直接对整个序列修改很阴间,所以不妨考虑每个位置。

可以将加法移到取minmax后面。于是需要求某个数取一波min和max之后得到什么。

因为后面的minmax有“决定性”。不妨考虑一个后缀,然后维护个\([L,R]\),表示前面小于\(L\)的能变成\(L\),大于\(R\)的能变成\(R\)。从后往前扫,如果某一刻出现了\(L>R\)就得到了答案。

用个以时间为下标的线段树维护。因为要处理每个数,可以离线,扫过去,支持加入操作和删除操作。

时间\(O(n\lg n)\)


LOJ3524. 「IOI2021」钥匙(口胡)

\(S_i\)表示\(i\)能到达的集合。如果\(u\)能到达\(v\),一定有\(S_v\subseteq S_u\)

因为要求最小。假设有\(x\)能到\(y\),现在想知道\(y\)是否能到\(x\),就让\(y\)走下一个到\(z\),想知道\(z\)是否能到\(y\)……如此往复,发现如果有个点之前走过,就将之前到现在这些点所在一起,继续做。

解释:有贡献一定是一些点集\(T\),满足它们的\(S\)都等于\(T\)。并且因为是求最小,按照上面一直走下去,如果走不下去说明当前一定是最小;如果走得下去就走。

随便维护一下。


7151. 【2021.6.28 NOI模拟】tennis

推一波式子,最终可以转化成求组合数一行的前缀和。

莫队搞,另外卡亿点常。


7152. 【2021.6.28 NOI模拟】bet

写出个平均数和平均数的平方的线性递推式,矩阵乘法即可。


7153. 【2021.6.28 NOI模拟】function

构造\(f=g*h\),使得:\(h\)有值的位置少,\(g\)前缀和好求。取\(g(i)=i^m\)发现\(h(i)\)只有powerful number处有值。

枚举后直接算。


7148. 【2021.6.29 NOI模拟】多项式时间哈密顿回路

二分+贪心。dfs,从祖先带下来个栈,在回溯的时候尝试用栈中的东西补。

存下dfs的进栈出栈序以及需要的信息可以做到寻址连续。


7149. 【2021.6.29 NOI模拟】AI高考数学134分

分治,假设\(a_{i..mid}\)是最大值,固定\(i\),看\(j\)\([mid+1,r]\)根据\(b\)\(c\)最大值所属分成三段,用前缀和搞搞。


7150. 【2021.6.29 NOI模拟】自动化leetcode

分块。处理出东西使得可以快速查出某个数通过这个块之后会变成什么。

模拟过程。假设当前定义域是\([l,r]\),如果\(a_i\)在其左右则很好搞,如果\(a_i\)跨过中间,就将比较短的那边长度翻过来,总长恰好减了那么多长度。于是时间是\(O(V)\)的。

这个过程中用并查集搞搞。实际上在做的过程中并没有用到查并查集中祖先的操作,所以可以做完之后再路径压缩。

适当分配块大小,时间\(O(n\sqrt V)\)


Codeforces Round #728 (Div. 1)

A:按照dis排序,连一条主链使得可以得到这些dis,然后连dis大的往dis小的连负两者差的边。

B:考虑\((u,v)\)的贡献。枚举\(rt\),设\(u,v\)路径上距离\(rt\)最近的点为\(x\),则贡献只和\(dis(u,x)\)\(dis(v,x)\)有关。设\(f_{i,j}\)表示这个贡献。相当于一个链上,左边\(i\)个点右边\(j\)个点,每次等概率左右扩展,问先扩展到最右边的概率。容易dp得出。


AGC054

A:假如两端不同一次就行;否则看看是否找到\(i\)满足\(s_1\neq s_i,s_{i+1}\neq s_n\),如果能找到就两步,如果找不到可证无解。

B:考虑两个人最终得到的数的各自的排列。发现想到得到这个结果,有且仅有一个总共的排列对应。容易直接构造得到。

C:设\(f_v\)表示\(v\)前面大于\(v\)的值的个数(\(v\)是值不是下标)。正着做的话,每次一定可以让某个\(f_v>K\)\(f_v\)减一,最终结束状态一定是所有\(f_v\)\(K\)取min。反过来,考虑有哪些状态做的结果是这个状态,显然就是对于所有\(f_v=K\)的位置,\(f_v\)原来可以取到\(\ge K\)。并且可证只要\(f_v\le n-v\)就一定存在方案且对应方案唯一。

E:令\(p_n>p_1\)。充要条件:\(\exist i\in [1,n-1]\)\(p_i\le p_1,p_n\le p_{i+1}\)

充分性:找到这个\(i\)。把值域根据\(p_1\)\(p_n\)分开,先从大到小依次插入\((1,i)\)中小于\(p_1\)的,再从小到大依次插入\((i+1,n)\)中大于\(p_n\)的,然后从小到大依次插入\((1,i)\)中大于\(p_1\)的,再从大到小依次插入\((i+1,n)\)中小于\(p_n\)的。

必要性:归纳。反证,在对于任意\(i\)都不满足的情况下,将序列分成两段,需要两段都可行。根据可行的必要条件推回来,发现和假设矛盾。

然后计数。直接容斥推不出。考虑求出不合法的。设以\(p_1,p_n\)为分界的三个部分有\(x,y,z\)个,则贡献为\((\prod_{i=y}^{x+y-1}i)(\prod_{i=y}^{z+y-1} i)\)(因为x的只能跟在x的或y的前面,z的只能跟在z的或y的后面,故能分开计算)。

推推式子,适当使用生成函数,就能做到\(O(1)\)计算。


6056. 【GDOI2019模拟2019.3.13】碱基配对

按照套路用FFT减法卷积搞一搞即可。


6058. 【GDOI2019模拟2019.3.13】false-false-true

如果分别计算每个点对终点的贡献,就是\(\frac{\min(i,j)}{i+j}\frac{\binom{n}{i}\binom{m}{j}}{\binom{n+m}{i+j}}\)。可以想到卷积但是有\(\min\)不好搞,于是要写分治FFT。用力卡常可以过。

ls的代数推法:对于递推式\(f_{i,j}=\frac{\min(i,j)}{i+j}+\frac{i}{i+j}f_{i-1,j}+\frac{j}{i+j}f_{i,j-1}\)。令\(g_{i,j}=f_{i,j}-\min(i,j)\),可以发现\(g_{i,j}=\frac{i}{i+j}g_{i-1,j}+\frac{j}{i+j}g_{i,j-1}-\frac{1}{2}[i=j]\)。然后计算每个\(i=j\)产生的贡献即可。

lzc的几何推法:令\(n\le m\)。画出个从\((0,0)\)\((n,m)\)的折线图,再画个从\((0,0)\)\((n,n)\)的直线。走的时候,每次如果往靠近直线的方向走就会有贡献(如果是算对的期望)。根据直线将折线划分,发现每段向下和向左的个数相等。于是总共走了\(n\)步有贡献。然而实际上如果恰好在直线上,方向不确定,会有\(\frac{1}{2}\)的贡献。于是另外计算直线上的点的贡献即可。


6057. 【GDOI2019模拟2019.3.13】小凯的疑惑

分块三层。最下面那层可以枚举所有情况,预处理,然后O(1)查。到第二层,一共有层长种可能,枚举之,并依靠下面那层的信息计算;到最上面那层,固定位移模第二层层长,枚举之,根据第二层信息计算。

调参和时间复杂度估计咕咕咕。


LOJ3525. 「IOI2021」喷泉公园

考虑没有四个点在同个格子的部分分。此时不会有相差恰好一个格子的竖线和横线。可以对格子黑白染色。黑色的格子负责染上边或下边,白色的格子负责染左边或右边。

魔改一下:还是黑白染色。先将所有可能连的边连上,然后依次从上到下,从左到右考虑每个方格。如果某个方格四个点都有,那就删掉左边(白格)或删掉右边(黑格)。

考虑这个删边的过程。在删边前,一直是联通的。要操作某个四方格的时候,由于钦定了顺序,它的边没有被动过,四条边连着;此时删掉其中一条,自然还是联通的。


LOJ3526. 「IOI2021」修改 DNA

IOI竟然有签到题。

钦定一个置换,答案为点数-轮换数。如果\(a_i=b_j\)则可以连边\(i\to j\)。不妨根据\((a_i,b_i)\)统计,然后先凑自环,再凑重边,最后三元环。


LOJ3527. 「IOI2021」地牢游戏

写题的时候忘记把临时变量赋值到倍增数组上了,时间复杂度直接假掉然而我调了半天参数。

看到如果\(\ge s_i\)则加\(s_i\),不妨根据\(z\)\(2^k\)分阶段。对于阶段\(k\),此时\(z\ge 2^k\),令\(s_i<2^k\)的战胜,\(s_i\ge 2^k\)的战败。用个倍增搞一搞,跳到第一次发现\(s_i\ge 2^k\)的战胜了,此时\(z\)就会大于等于\(2^{k+1}\),到达下一个阶段。

总结:如果每次战胜一个之前没有战胜的,就更新倍增数组,这很亏;划分阶段,这样就把更新倍增数组的次数收束到了\(O(\lg V)\)次,并且由于如果忽然战胜了个\(s_i\ge 2^k\)就可以跳到下个阶段,这样就保证了正确性。

理论上时间\(O(q\lg^2V)\)。为了卡空间写了个非二进制的倍增(前面几步可以暴力,能省很多空间)。实际上也可以链剖+二分,环上特殊处理。因为不想处理环相关操作所以没写哪个。


7157. 【2021.7.3 NOI模拟】猜猜

用个set维护相邻的。对于每个点记个\(pre_i\)。再用个线段树维护个\(pre_i\)最大的,找的时候线段树上往后找\(k\)个。时间\(O(nk\lg n)\)

我的方法比较蠢,维护了区间中\(pre_i\)的前k大,时间复杂度一样的。


7159. 【2021.7.3 NOI模拟】是谁(口胡)

暴力题……适当压位,以及将多个操作压在一起,用某些手段搞搞……

现在才知道角谷猜想没有被证明,亏我比赛时给它证了好久……


100207. 决心

正确地玩过之后发现如果长度大于\(2\)则只需要操作2次。具体构造方法:任选某个点\(x\),其前驱后继分别为\(z,y\),连边\(z\to x\to y\),操作\(z\)\(y\),就可以把\(x,y\)分到一起然后\(z\)连向\(y\)的后继。然后因为\(z\)被操作了,所以\(z\)要成为新的\(x\),继续操作,后面就是唯一的了。所以操作一个环的方案数是环长次。

然而可能会有两个环合并到一起的情况。发现由于合并的时候之前操作的两个点不能操作了,以它们分界的两部分必须要对称。所以只能是两个大小一样的环合并在一起。

于是对于同环长,贡献为\(\sum_{2i\le c}\binom{c}{2i}i!!L^{c-i}\)

枚举所有本质不相同的情况计算即可。


6132. 【NOI2019模拟2019.4.18】构图

如果全部是正数或负数,策略就是:按照绝对值从小到大排序,枚举一个长度为偶数的前缀,这个前缀内部两两配对,配对互相包含(即小的配大的)。其它的点都和一号点连边。

如果两者都包含,显然正数要连负数。枚举负数的一段前缀,用上面的方法做;然后后面的负数和前缀依次连边,绝对值最大的负数可能连多个正数。

可以做到\(O(n^2)\)。也可以用FFT优化但是没必要。


6088. 【GDOI2019模拟2019.3.27】白

暴力可以预处理出\(A^i\),后面的部分用多项式操作和FWT解决。

前面这个暴力\(O(n^3m)\)太慢。实际上可以求出\(A\)的特征多项式,于是可以得到\(A^{k}\)关于\(A^i,i\in[k-n,k-1]\)的递推式。这个递推式只需要按位相加。

对于每个FWT中的状态,大概能求出个序列\(F(x)\),由于已经知道是递推所以可视作\(\frac{P(x)}{Q(x)}\)\(P(x)\)可以通过\(F(x)Q(x)\)取前面\(n\)项得到。然后要求\(\frac{1}{1-(\frac{P(x)}{Q(x)}-C)}\),化简之后直接多项式求逆即可。

求特征多项式可以暴力插值搞,也可以不求后面直接BM出递推式。

全程其实都可以不用FFT操作,常数够小。


7160. 【2021.07.06 NOI模拟】合成小丹

每次合并两个,把这个过程画出来可得一棵非叶子节点都有两个儿子的二叉树,叶子的贡献是\(\frac{a_x}{2^{dep_x}}\)。并且\(\sum\frac{1}{2^{dep_x}}=1\)。反过来,如果钦定了\(dep_x\)满足这个条件,就一定可以构造出\(dep\)分布是这样的树。

按位确定。问题变为:有个\(s\),要求选择某些点,使得\(\frac{a_x}{2^{dep_x}}\subseteq s\)。对于每个\(x\),有个\(dep_x\)可以取到的集合\(D_x\)。现在还需要满足\(\sum\frac{1}{2^{dep_x}}=1\)。先看看有没有能选\(dep_x=0\)的,如果没有再看\(dep_x=1\)的,能选就选。总体概括为:现在将当前点集分成\(c\)组,每组贡献\(\frac{1}{2^k}\)。如果存在方案,并且刚好存在某个能取到\(dep_x=k\)的,可以将它所在的组变成它自己,其它组员任意丢到其它组,然后\(c\)减一变成子问题;如果找不到,就继续细分找下一层。于是就证明了贪心的合理性。

一层一层做,直接模拟上面的过程是\(O(nw^2)\)的。可能TLE。

观察,如果\(\sum \frac{1}{2^{dep_x}}\ge 1\),我们必然能找到个子集使得\(\sum \frac{1}{2^{dep_x}}=1\)。于是所有\(dep_x\)\(\min(D_x)\),判断是否\(\sum \frac{1}{2^{dep_x}}\ge 1\)即可。(这样也证明了上面那个贪心的合理性,不过从上面推到这里好像不行)

维护\(\sum \min(D_x)\)。观察\(s\)\(p\)位从\(1\)变成\(0\)\(D_x\)的变化,有D[x]=D[x]&~(a[x]>>p)。于是就可以做到\(O(nw)\)了。


7161. 【2021.07.06 NOI模拟】路过中丹

判定条件:包含一个长度为\(3\)的奇回文串,或能被若干个偶回文串覆盖。

考虑从中点开始往走,要求每步相同。如果有奇回文串,就可以先一起走完所有点到中间,分别到两边停下来;如果没有奇回文串,从中点往两边走,发现不能恰好一个转向(否则有奇回文串),于是只能走偶回文串。

求出包含\(i\)的回文串中左右端点最小的偶回文串\([L_i,i],[i,R_i]\)。如果不合法,那么存在\(i\in[l,r],L_i<l,R_i>r\)。用数据结构搞搞即可。可以做到\(O(n\lg n)\)

题解做法是分治。对于\([l,mid]\)中的点,设\(Right(i)\)表示若干个偶回文串覆盖\([l,mid]\),最左到\(l\),最右最小是多少。另一边也记个\(Left(i)\)。询问的时候就看\([Right(l)\le r\and Left(r)\ge l]\)。处理\(Right\)时,从右往左做,搞出个转移方程(枚举\(i\)为左端点的串),然后借助回文自动机维护。直接做要回文自动机上倍增。发现转移时,如果下一个转移的长度超过上一个转移的一半,那么上一个转移完全可以用两个下一个转移替代。于是只需要保留\(O(\lg )\)种转移。维护个转移位置的指针,分治过程中从上层到下层指针移动单调。总时间复杂度是\(O(n\lg n)\)


7162. 【2021.07.06 NOI模拟】膜拜大丹

画出坐标\((i,a_i),(b_j,j)\)。如果两者是左上-右下分布就是个二元环。考虑一个环,它一定存在个左上-右下分布的边,那不如替换成边形成的二元环。

后面直接贪心就行了。扫描线,用set维护,找最紧的。

题解转成了找最大独立集,于是变成了格路问题,走个从左下到右上的,每次向右向上,贡献为格路上方的\(B\)和下方的\(A\)。写出DP之后进行了一波分析、优化、数据结构得到正解。


LOJ3175. 「IOI2019」排列鞋子

假如钦定一个排列表示最后到哪里,那么排序的逆序对个数就是答案。

对于存在一种方案,考虑其排序后相邻的两对鞋原来的相对位置,看看对其调整能不能更优。于是可以得到:如果某对鞋二维偏序小于另一对鞋(两维分别为其所在位置的最小值和最大值),那么就一定排在前面。

钦定一个顺序使得二维偏序小的一定在大的前面,然后就过了?


7164. 【2021.07.08 NOI模拟】七管荧光灯

看做“杏仁”。发现连接端点的路径不能存在两条同时完全操作。

结论:如果各路径上权值相同,三条路径权值异或和为0,先手必败。

证明:显然必败态不能变成必败态;如果不是必败态,设各个路径最小值为\(x,y,z\),然后\(x,y,z\)中取一个像nim游戏那样调整一个值使得异或为0。将其它值都调成其所在路径上的最小值。于是就一步到达必败态。

后面就是ljDP。


7165. 【2021.07.08 NOI模拟】混乱(口胡)

wmy的做法:

平衡规划。\(k\le T\)时,找出包含\([S_i,S_j]\)的区间中权值最小的区间;\(k>T\)时,直接\(O(n\lg n)\)搞过去,这部分时间\(O(\frac{n^2\lg n}{T})\)。前面部分:分块,每个点存包含它到后面每个块尾的权值最小区间,线段树维护之。一次修改\(O(\frac{n}{B}\lg n)\)。询问时:先处理右端点超过询问右端点所在块的区间的贡献,对于散块,因为随机所以可以看成\(O(B)\)个有影响的区间,离线一下询问(一个操作中的查询\([S_i,S_j]\)),跟这些有影响的区间归并一下,时间似乎是\(O(B\lg n)\)

感觉时间是\(O(n\sqrt n \lg n)\)的。


【2021.07.08 NOI模拟】超立方体

老原题了。

核心发现是:可以通过查\(d(x,rt)\bigoplus d(y,rt)\bigoplus d(x,y)\)得到\(LCA(x,y)\)

按照老套路增量+维护虚树重链剖分即可。

我写了随机链剖。不过实测一条链的有一点概率会挂,加了个表现优异的优化:

在重链上二分那一部分,考虑求出插入点和其它每个点的LCA的异或和,显然这个东西应该是祖先的点异或和 异或 插入点 后代的点的个数次。这个东西由插入点的最近祖先唯一确定。要找最近祖先,相应地求出的这个东西,要求跟上面问的相等,这是个必要条件。

在满足这个必要条件的集合里二分。如果要卡,那么需要中间一坨点异或和为0或者为插入点这样的数据,应该不好造,况且我本来就是随机增量,就更难卡了。于是这部分就变成几乎\(O(1)\)啦。优化后链的大概跑20000。


7167. 【2021.07.12 NOI模拟】简单的希尔伯特曲线题

结论:行的和相等。

证明考虑从头尾同时走,任意时刻两点位置关于中轴对称。

知道之后分类讨论,递归即可。


7169. 【2021.07.12 NOI模拟】简单的bzoj题

老原题了。

写出个DP,线段树维护区间答案。这个DP是凸的所以可以闵科夫斯基和。

对于询问,先套个wqs二分,找到线段树对应若干个区间,在上面二分得到当前最优值。时间\(O(n\lg^2 n\lg V)\)能过。

如果wqs二分用个整体二分,线段树各个区间中最优值的候选位置在整体二分中每层状态的总长为区间长,可以省去后面那个二分,时间\(O(n\lg n\lg V)\)


7168. 【2021.07.12 NOI模拟】简单的字符串题

比赛时为什么没有想过求两个位置的LCP啊……

第一问:把贡献关于位置差和LCP的关系式写出来,化一下。可以在后缀树上强行做,线段树+dsu on tree,时间\(O(n\lg n)\);也可以枚举位置差\(d\),在\(kd\)的位置放个观察点,相邻位置查LCP和LCS,搞一搞,时间\(O(n\lg n)\)

第二问:如果建SAM自然最方便;我因为写了SA不想写SAM,就这样:考虑SA其实相当于后缀树上dfn,height相当于两两LCA。维护一条祖先后代链上每个点的贡献。按顺序遍历SA,每次先将height后面的贡献清空,然后问链和,再对链区间加。时间\(O(n\lg n)\)

PS:不会卡常于是将ST表的前后两维交换就过去了?(交换后前一维表示跳的步数,后一维表示起点)


7170. 【2021.07.13 NOI模拟】伽铵目

\(f_i\)表示sg为\(i\)的树的大小最小是多少。显然\(f_i=1+\sum_{j=0}^{i-1}f_j\),得到\(f_i=2^i\)。于是sg的级别是\(O(\lg n)\)的。

搞个暴力:\(g_{i,j}\)表示\(i\)为根,sg值位\(j\)的方案数。转移的时候用个状压DP,用FWT优化。

另外有个结论:sg为\(k\)的点数是\(O(\frac{n}{2^k})\)级别的。大概说明一下:首先假设子树不相交,那么每个都有\(2^k\)的点数;考虑两个这样的点为祖先后代关系,中间没有其它这样的点,那么最多算多了\(2^{k-1}\)的贡献,剪掉。于是摊下来每个点至少有\(2^{k-1}\)的贡献。

时间\(O(n\lg^2 n)\)


7171. 【2021.07.13 NOI模拟】笛镭特

直接用ETT模拟即可。

其实可以不用splay。处理某点之后,先处理子树内的,然后将整个子树区间赋值(删除),再搞祖先的。


7172. 【2021.07.13 NOI模拟】镁克锶

卡空间卡时间然后放个bitset+分块过。

题解:分块,用bitset维护块的区间的颜色。

我的考场做法(70分):定期重构,维护主席树,线段树上二分的时候暴力往下找,如果找到时间块内动过的就不理它;时间块内动过的另外用个set处理。空间\(O(n\lg n)\),时间\(O(n\sqrt n\lg n)\)

正经的\(O(n\lg^2 n)\)时空做法:先在外面套一层维护权值区间信息的数据结构,内层要查这个权值区间中,是否有值不在询问区间中出现过。对于每个值,根据其出现位置将序列划分成若干区间。我们想问询问区间是否被其中一个区间包含。可以在划分的区间中,每个右端点上挂个左端点的位置;然后以询问区间右端点为开头的后缀中找挂的最小的左端点位置。内层需要用个支持单点修改,区间查询最小值的线段树,另外需要在叶子中维护个set以插入删除。


Codeforces Round #732 (Div. 1)

A:先排序。颜色相同的块内部交换一下,大概是有个01序列,每次可以把00变成11或反之;可以发现可以转化成交换距离为2的,然后再搞;于是先分位置奇偶性排序,看看排完之后是否前面全0后面全1。其实也可以一开始就分奇偶性排序,然后看整体是否已经有序。

B:把原串拆成0,010,11,发现这些之间可以任意移动,另外一堆11也可以和一个010组合起来。枚举多少个11用于组合,记个数。

C:建图,如果两个排列有公共点就连边。如果当前存在一个排列,存在(颜色,位置)的二元组独属于这个排列,那么它一定要被选,选上之后删去和它相连的点,并且消去它和它们的影响。一直这样搞搞。如果不存在这样的排列:假设之前消过\(x\)个,由于一定存在和它们配对的,所以至少消掉\(2x\)个排列;现在未确定的(颜色,位置)是\((n-x)n\),而总数不超过\((2n-2x)n\)。根据鸽巢原理,此时所有(颜色,位置)恰好出现了2次。连边,此时一条边两端点选和不选的状态是相反的,所以可以黑白染色。因为保证有解所以没有奇环。

D:不太能确定各个等差数列是什么,于是用代数方法搞搞。各时刻的位置和显然是等差数列,于是可以确定第一个答案,并且知道修改的增量;再搞出此时的平方和应是什么,现在是什么,得到修改后平方和的增量;根据两者列个方程可解。


7175. 【2021.07.14 NOI模拟】种蘑菇

稍微推一推可得\(S\)的贡献为:\(\sum_{t|u\in S}\sum_{d|t}d^{|S|}\mu(\frac{t}{d})\)

枚举\(d,t\),提取所有作为\(t\)倍数的点生成的子图,算可能的\(S\)的贡献和。因为已经枚举了\(d\)所以不需要记\(S\)的大小。

时间是\(O(n\lg^2 n)\)


7173. 【2021.07.14 NOI模拟】按钮

普通暴力:记个\(F_{l,r}\)表示当前数为\(l\),确定目标在\([l+1,r]\)所花的最大步数;\(G_{l,r}\)记个对称的。转移的时候枚举个\(md\)然后分成两个子问题。

因为dp值不大(题解说是\(45\))所以换一下状态和dp值。记\(f_{l,c}\)表示当前数为\(l\),最大步数至多为\(c\)\(r\)最大能是多少;\(g_{r,c}\)类似。

转移:\(f_{l,c}=\max_{g_{md,c-\Delta}\le x+1}f_{md,c-\Delta}\)\(\Delta\)表示操作这一轮的代价。

优化:最外层枚举\(c\)。记个\(D_s\)作为转移的中转。\(s\)形如一个数被挖掉了几个空的形式。于是从\(l\)变成\(md\)相当于先变成\(s\)再变成\(md\)。一开始将\(f_{md,c-\Delta}\)(此时枚举了\(md\)要挖掉哪里)的贡献挂在点\(g_{md,c-\Delta}-1\)上,然后从左往右扫,扫到某点把挂在上面的贡献加入其对应的\(D_s\)中,算\(f_{l,c}\)的时候枚举\(l\)挖掉哪里,然后用对应的\(D_s\)转移。

时间大概是\(45*2^5*10^5\)


7174. 【2021.07.14 NOI模拟】蛋糕

假如已经固定了\(x\)。把\(x\)没有穿过的拉出来,变成个二维的问题。

选择的\((y,z)\)可以看做个点,一个矩形被穿过当且仅当它对应的十字架中包含这个点;于是我们希望知道所有十字架交集是否为空。

算补集的并。拆成四个角,每个角维护个阶梯。统计的时候,先搞出左下、右下的分界点和左上、右上的分界点,然后把横坐标分成三段,每段的上下边界分别由左上左下、左上右下/左下右上、右上右下决定。维护上下边界的差,如果区间中存在差大于0则有解。

阶梯可以用set暴力维护。因为一个点的存活时间是一段前缀和一段后缀,不妨拆成两个点看。从左到右扫,如果新增了个时间为一段后缀的点,它覆盖的点一定不会恢复;如果删除了个时间为一段前缀的点,它刚好覆盖的点会暴露。每个点只会暴露一次。如果知道哪些点被暴露,之前先反过来操作一遍,此时这个点加入之后覆盖的点,就是那时删除后暴露的点。


AGC026C String Coloring

发现如果决定了左半边的状态,整个字符串就确定了。折半统计即可。


AGC026D Histogram Coloring

先决定最下面那行。考虑倒数第二行。如果存在相邻相同,那么方案确定;否则可以继承或取反。有了高度的限制,相当于往上搞的过程中删掉了一些点,分裂成几个问题。对其DP,考虑两个最近的存在相邻相同的位置,它们之间的贡献:先求出各自的失效位置(即哪个小),以此作为区间搞个类似于下包络线的结构,超出包络线的极长横区间个数(2得到这个东西次方)。


AGC026E Synchronized Subsequence

首先划分出若干个极小的a,b出现次数相等的组。每组中每对ab的先后顺序是相同的。

考虑局部答案:

1类:如果a在b前出现,答案一定是ab的循环。如果出现aa那么一定可以通过删掉后面那些将其变成ab。

2类:如果b在a前出现。可证如果第i对ba出现了,第i+1对ba也出现会更优。

全局答案:

从后往前维护个字典序最大的(显然不同后缀加上相同前缀大小关系还是由后缀决定)。

如果是1类,并且后面没有出现过2类,那就放最优解。

如果是2类,局部最优解的候选两两不互为前缀,所以肯定取局部最优解;用局部最优解+当前答案和当前答案比较,取最优。

时间\(O(n^2)\)


AGC033E E - Go around a Circle

不妨设\(s_1=R\)。首先考虑第一步,可得不存在连续的BB,否则在之间的点走不出第一步。

考虑环上每个R的连续段。s中这么长的第一段R中,这个连续段每个点都要跳那么多步,到了最后都应该到达端点。如果段长为偶数,那么总是存在点跳不到端点,所以段长一定为奇数。另外也得到了个段长的限制。

在s的第一段之后,s的每一段开始,都是从R的连续段的两个端点出发。跳那么多步又要跳到端点,根据奇偶性和长度又得到了段长的限制。

于是问题变成了:染色,B段长度为1,R段长度为奇数且有个最大值限制。

对其计数。特判下没有B段的情况。后面将R段和B段合并到一起,变成将环划分成若干个有长度限制的段(要判\(n\)为奇数)。然后用生成函数随便推推就可以得到\(O(n)\)的递推式。


LOJ2769. 「ROI 2017 Day 1」前往大都会

好像和NOI2019那道题差不多?

首先建出最短路图,根据拓扑序进行DP。对于单个极长的铁路进行分析,列出转移方程,可以斜率优化。

于是每个极长的铁路维护个斜率优化用的队列即可。


LOJ3472. 「JOI 2021 Final」地牢 3

考虑贪心策略:考虑当前点如果吃饱最多能走的范围,如果范围内能找到比它小的,就从这个点花尽量少的代价,使得体力值能够到达那个第一个比它小的(中间不吃);否则范围内的都比它大,那就在这个点吃饱。

我想了个LCT做法。设\(p_x\)是第一个比它小的。如果\(p_x\)在范围内,那么连黑边\(x\to p_x\),否则连白边\(x\to x+1\)。询问的时候提取\(l\)到最后的路径,找到在\(r\)之前的最后一个黑边,算出\(l\)到这个黑边的贡献,再加上黑边直接到\(r\)的贡献。至于如何算路径的贡献,我本认为如果跳一次黑边那么一定体力值清空,列出贡献的式子之后,以黑边分段分析,显然是可以方便维护的。然后离线,枚举\(U\),变化的时候改变一下边。

然而如果出现了\(x\to y\to z\)\(b_x<b_z<b_y\)的情况,\(y\to z\)是黑边,但是由于\(z\)不是\(x\)考虑的更小的点,所以有可能在\(x\)吃饱,跳到\(y\),跳到\(z\)之后还有剩余。这就假了。

《如果是在考场上我就直接上了》

靠谱的做法:从后往前维护个单调栈(后缀的前缀最小值),弹栈的时候(栈顶大于当前点)讨论加入点和栈顶和栈顶下一个的关系。本来应该是从栈顶到栈顶下一个,现在考虑用当前点补充体力尽量替代栈顶补充体力然后再到栈顶下一个,讨论一下。至于\(U\)的限制,可以维护个以\(U\)为参数的函数,用数据结构对这个函数进行修改。


LOJ2288. 「THUWC 2017」大葱的神力

前面7个点各有各的确定性做法,后面的用random_shuffle或退火乱搞一下。


LOJ3476. 「ROIR 2021 Day 1」绳子

可以转化为要将一些\((a_i,b_i)\)拼接,要求\(b_{i}+a_{i+1}=d\)

如果\(d\)定:把\((a_i,b_i)\)看成平面上的点,根据限制可以画一条\(x+y=d\)的直线,\((a_i,b_i)\to (a_{i+1},b_i)\to (a_{i+1},b_{i+1})\)。看到此时\((a_i,b_i)\)出度入度为\(1\),不妨直接将其看成\(a_i\to d-b_i\)的边。

连边之后跑欧拉路径即可(注意判连通性)。

如果\(d\)不定。我们希望\(a_i\)\(d-b_j\)尽量两两配对。那大概是\(a_i\)小的配\(b_j\)大的。如果能形成回路那肯定就是最小配最大,如果只是路径有路径端点,就用\(a_i\)最小次小配\(b_i\)最大次大跑一遍。


LOJ3067. 「ROI 2016 Day2」二指禅

暴力直接设\(f_i\)表示匹配到\(i\)。处理前缀转移时用\(f_i\)转移到\(j>i\),处理后缀转移时用\(j<i\)转移到\(f_i\)。lhf管这叫主动转移和被动转移。

平衡规划。字符串长小于\(B\)时用上述暴力;大于\(B\)时,求出其和各个位置的LCP,LCS,用数据结构维护个:区间修改(取min)+单点查询,区间查询+单点修改。分析下可以把前者的区间修改换成前缀修改,后者的区间查询看成后缀查询,这样就可以用\(O(\sqrt n)-O(1)\)数据结构啦(用点整块前缀min和散块前缀min)。总时间\(O(n\sqrt n)\)

lzc的nb做法:一个串的最大border应该只出现了两次。还是平衡规划,现在处理大串前缀的转移(后缀的转移可另外做)。建出border树。从前往后扫,现在搞出了当前位置能够匹配的最长前缀(当前位置作为末尾),知道了对应的节点。考虑一个border的等差数列,对比一下上次它们出现时开头的位置(即决策点候选),以及现在时开头的位置,发现基本上重复,除了那个最小的border。所以一段只需要改一下。

这个做法尽管时间复杂度劣一些,但好像也有优点:它只用到了被动转移,意味着主动转移不方便的情况下它很好做(比如把题目的匹配串换成个Trie)。


LOJ3290. 「CEOI2014」蛋糕

考虑起点一边。如果\(i\)\(i+1\)前面被吃,并且\(a_{i+1}<a_i\),那么吃掉\(a_i\)之后一定会立刻吃\(a_{i+1}\)。把这样的\(a_{i+1}\)删掉,得到起点两边的阶梯状的东西。

用set维护一下即可。处理修改的时候我偷懒用了10log,实际上也可以10+log,甚至log^2。


UNR5

D1T1:

考虑倒过来做:设\(dp_{i,j}\)表示第\(i\)对括号,它和包含它的括号中有\(j\)个选B。每个状态记个0..3次方和。

时间\(O(n^2)\)

D1T2:

首先处理树同构,将同构的树压在一起。于是变成一棵新树,节点\(u\)记个\(c_u\)表示有这么多个长成\(u\)子树这样的子树压在了一起。记个\(f_u(x)\)表示\(u\)子树中方案数的EGF。设\(g_u(x)\)表示\(c_u\)个这样的树组合起来的方案数,于是有\(g_u(x)=\sum_{i=0}^c\frac{(f_u(x)-1)^i}{i!}\)。求\(f_u(x)\)就将儿子的\(g\)卷起来之后乘上\((1+x)\)。于是就能做到\(O(n^2)\)

正解: 搞个特殊的重链剖分,只认严格重儿子。那么重儿子贡献一定是直接用\(f\)乘上来的。于是对于一条重链,就是重链上挂的一堆轻儿子的\(g\) ,以及重链长度个\((1+x)\) 卷起来。这里可以用合并果子FFT。然后求\(g\)的时候,可以用分治FFT来求。\(G(x)=\sum_{i=0}^c\frac{x^i}{i!}\) , 求\(H(x)=G(F(x))\)

\[G(x)=G'(x)+\frac{x^c}{c!}\\ G(F(x))=G'(F(x))+\frac{F^c(x)}{c!}\\ =\frac{1}{F'(x)}[G(F(x))]'+\frac{F^c(x)}{c!}\\ H(x)=\frac{H'(x)}{F'(x)}+\frac{F^c(x)}{c!} \]

这个东西可以先求出\(\frac{F^c(x)}{c!},F'(x)\)之后分治NTT。

总时间复杂度\(O(n\lg^2n)\)。 (好像如果不合并果子FFT就有\(O(n\lg^3n)\)

D1T3:

结论:一个dfn序合法,当且仅当:对于所有从点\(x\)到点\(y\)的移动,\(dfn_x<dfn_y\)或者\(x,y\)为祖先后代关系。

必要性:对于某个子树,比这个子树大的值进不来;因为执行过程中子树不能变大,所以还是进不来。

充分性:构造证明,每次找\(dfn\)最小的叶子,然后把目标位置为它的值移过来。移动的起点此时一定是它的祖先,并且移动之后其它点的相对顺序不变,仍然满足结论,归纳。

进一步观察:只要每次搞某个点的时候,起点都在祖先就行。往前分析,在前面也满足这个条件的情况下,可以把祖先链看成个集合,每次放些东西进去,然后把需要的取走。如此,只有对于每个点而言,起点的\(dfn\)不超过其子树的最大\(dfn\)才能满足。即\(a_x\le out_x\)

我们考虑\(dp\)出每个点\(out\)的下界。设\(dp_i\)表示\(in_i\)(不要以为是out然后搞错了后面的结论)的下界,通过调整法证明,按照\(dp\)值从小到大排序转移最优。

D2T1:

讨论一下中点之后,大体上是要找到相同的两段字符串。在分界点对齐处分段,每段大概是上面12222下面22221这样。此时如果将长为2的连边,长为1的和0连边,于是就变成了从0开始跑欧拉回路。

以上只是大概,细节不论。

D2T2:

\(w=128\)。可以暴力每次用线段树找到要修改的位置并改之,乍看下去是\(O(nw^2\lg n)\)。经过PT分析,这实际上是\(O(nw^2+qw\lg n)\)。不妨先考虑只有一种修改的情况,我们容易认为是\(O(nw\lg n)\),实际上可以对于线段树上的每个区间分析,每次对一个区间进行整体修改,势能就减少\(1\)。线段树上\(n\)个区间于是只有\(nw\)的势能。考虑两种修改,发现除法可能会使得势能增加,但可以把这部分势能摊到\(q\)上,变成\(qw\lg n\)

这个东西本身常数不大,加了个底层暴力就过了(

正解:考虑一个普通的做法,除法递归下去暴力修改,and打tag,对于每个位维护出现次数。这样时间大常数\(O((n+q)w\lg n)\)。每位用\(w\)个数存状态,每次合并需要\(w\)个数对应相加,这样太慢,换成直接ll普及的那个转置之后压位用位运算模拟加法的东西,每次操作是\(O(\lg V)\)。还要处理将某些位上的数清零,发现用这种形式其实也很方便。于是时间优化到了\(O(nw+q\lg^2n)\)


AGC021D - Reversed LCS

考虑从两边从中间做,搞两个指针,在指针相遇的地方处考虑,发现后面可以倒着走另一个指针之前走过的地方(也就是说结果一定是个回文串)。

于是决定走过哪些地方。先DP个没有修改的配对的位置,然后在这些位置之间插入一些通过修改产生的配对的位置。设\(f_{i,j,t}\)表示指针分别为\(i,j\),没有修改的配对的位置之间能插入的空隙长度和为\(t\),此时长度为多少。


LOJ3005. 「JOISC 2015 Day 4」Limited Memory

对于每个位置,假装所有括号颜色相同地找到与其对应的括号,判断颜色是否相同(注意不管这个位置是左括号还是右括号都要做)


LOJ3350. 「CEOI2020」星际迷航

不是所有博弈题都是非用SG函数不可的……(不过好像也能做只是时间乘了几个log?)

从后往前,考虑维护后缀的必胜必败的方案数(定根)。现在接上一棵树,选择其中一个根节点和另一个和后缀相连的点,计算新的必胜必败方案数。用DP的方式思考(因为便于换根),设\(h_{x,0/1,0/1}\)表示\(x\)子树中,插入了一棵必胜/必败的树,现在从\(x\)出发必胜/必败的方案数。

换根地求出这个东西之后,可以把每次的贡献写成矩阵,然后矩阵乘法即可。


LOJ3337. 「BalticOI 2020」病毒

容易想到在后缀自动机上做。设\(f_{i,s,t}\)表示把第\(i\)个串展开后,后缀自动机上从\(s\)\(t\)的总长,最小是多少。

每次转移,序列表那么长不太方便,于是就拆成len个点表示其的每个前缀。然后就可以把每个序列看成长度为2的。

转移可以看成:\(f_{x,s,t}\leftarrow f_{a_x,s,u}+f_{b_x,u,t}\)

用类似于Dijsktra的方法转移即可。


AGC017D

考虑SG函数。如果已经求出了某棵子树的SG,现在加一个点作为根连向这棵子树。对于原树所有状态,都恰好对应着原树上加个根。则原来只有一个点的状态对应两点相连,此时SG为1;并且发现每个状态都可以通过删掉和根相连那条边,得到SG为0。因此SG函数加一。

于是某个点的SG就是其儿子的SG加一的异或。


AGC029E - Wandering TKHS

考虑从\(x\)走到\(1\),必经路上有个最大值\(m\)。有性质:扩展的所有点都不会大于\(m\)

\(1\)为根建树,在刚好看到\(m\)的时候,一定会将\(x\)能直接到达的所有小于\(m\)的位置全部走完,再去走\(m\)。小于\(m\)的位置全部走完之后,\(x\)便无法到达\(m\)子树中其所属子树的其它点。于是\(m\)子树中\(x\)所属子树已经固定了。

\(m_x\)\(fa_x\to 1\)路径上的最大值。\(Q(x,v)\)表示从\(x\)开始在子树内扩展所有不超过\(v\)的点数(不包括自己)。假设已经求出\(c_u\),现在要求其儿子\(v\)的答案\(c_v\),考虑其答案变化\(\Delta=c_v-c_u\)

如果\(v>mx_u\),则\(u\)之前一定不会扩展到\(v\)。如果从\(v\)出发,\(v\)子树内会扩展\(Q(v,mx_v)+1\)的节点,考虑\(v\)子树外,这部分相当于从\(u\)开始扩展。于是\(\Delta=Q(v,mx_v)+1\)

如果\(v<mx_u\),则\(u\)之前已经扩展到\(v\)\(v\)子树外的部分仍然相当于从\(u\)开始扩展,不变,\(v\)子树内的增量是\(Q(v,mx_v)-Q(v,mx_u)=\Delta\)

问题变为如何计算\(Q(v,mx_v)\)\(Q(v,mx_{fa_v})\)

用数据结构有若干种计算方法。实际上直接记忆化搜索(用\(Q(x,v)=\sum_{y\in son(x),y<x}(Q(y,v)+1)\))),状态总数是\(O(n)\)的。

比如说计算\(Q(v,mx_v)\),需要用到\(Q(x,mx_v)\);后来又计算了\(Q(x,mx_x)\)。如果\(mx_x>mx_v\),则在链\([v\to x)\)中出现了个比\(mx_v\)大的点,那么算\(Q(v,mx_v)\)的时候理应是到不了\(x\)的,矛盾。

其它的也类似一波分析,大概就是枚举一个点可能存在的两种不同状态,在什么条件或者矛盾时两者才共存。题解说一个点至多有3个。

于是时间\(O(n)\)

posted @ 2021-06-13 11:07  jz_597  阅读(1042)  评论(0编辑  收藏  举报