乱七八糟的都先放这里了2

NOI模拟赛17-49泛做

NOI模拟赛49

T3

深深感觉到自己的弱。。。(看了>3h?

从头讲起,先是我自己的解法,首先显然可以转换成一个有向图判环问题。首先想到的是如何判断两个矩阵相交,因为有初始矩阵互不相交的条件,所以可以发现实际上A与B相交,A必有B四个顶点中的几个,B同理。所以就进行一个KDT上bfs判环,时间O(nsqrtn),空间O(nsqrtn)

然后讲题解做法一。就是转化判交条件,先考虑一维,若[l1,r1]与[l2,r2]相交,那么f[l1,r1]与g[l2,r2]相交,或f[l2,r2]与g[l1,r2]相交。其中f[l,r]是[l,r]在线段树上拆出的区间,g[l,r]是线段树上[l,r]所有子区间,g[l,r]包含f[l,r]。这个证明可以自己思考1h,二维类似。然后题解直接扔了一个树套树,这里讲下。就是现在bfs到一个点,我要query他的未达过子节点,那么自然达过的就删掉,我们压矩阵上树套树,fa为子树内所有既有信息集合(和分),然后用定义,先找到f[l,r],然后用每个f[l,r]含的区间对应节点上所有信息取下来,就是能达,注意这一块是考虑 g [ l , r ] g[l,r] g[l,r](当前)与 f [ l ′ , r ′ ] f[l^{'},r^{'}] f[l,r],虽然用的是f来做。另一部分是未和分的树套树,在线段树根节点向下扫直至整块(类似压时的遍历拆矩阵过程),易证也是 O ( l o g 2 n ) O(log^2 n) O(log2n),然后就把这些节点上的信息都取过来,相当于考虑 f [ l , r ] f[l,r] f[l,r](当前)与 g [ l ′ , r ′ ] g[l^{'},r^{'}] g[l,r]。时空 O ( l o g 2 n ) O(log^2 n) O(log2n)。然后把内层线段树离散化一下就空间降O(logn)。(但是有两棵树套树??感觉理解错了。。。)

讲做法二。再尝试优化过程,我们扫描x轴,y轴用原法维护,相当于主席树支持加区间删区间,可以做。然后我们再考虑如何交,发现就是树套树一层拍扁O(1),时空O(logn)。

NOI模拟赛51

T1

题目描述一坨大便吧。。。

简化就是可以一个森林,可以子树加,要求每个点数值在范围内。

考虑一个DP设每个点为 f i , j f_{i,j} fi,j,表示第i个点,权为j的最小次数。一次子树加相当于就是改权,所以 f i , j = m i n ( f i , j , m i n ( f i , k ) + 1 ) f_{i,j}=min(f_{i,j},min(f_{i,k})+1) fi,j=min(fi,j,min(fi,k)+1)。转移显然。

然后就 O ( n 2 ) O(n^2) O(n2)了,考虑优化,发现每个点只有两种取值, m i n ( f i , k ) min(f_{i,k}) min(fi,k) m i n ( f i , k ) + 1 min(f_{i,k})+1 min(fi,k)+1,先设每个都是后者,然后有一颗线段树储存了有哪些为前者。

那么要维护就是线段树的对位加,用线段树合并实现。还有要区间保留,也可实现。然后就是get新的min并更新线段树,那么就是先全局min,然后考虑到总共叶子在O(n)级别,就暴力跑把非最小的从线段树中删了。

共O(nlogn)。

现在nfls集训停了,终于有时间补了。

NOI模拟赛25

T1

首先最大的很简单,我们发现这个取的模式就符合我们要求最大的贪心原则,所以可以把两个合到一起根据题目所给的贪心方式贪即可。

然后发现第二问这种网络流/dual我就根本不熟QAQ。

方法一:我们首先转化一下题意。我们发现假设给信息的天集合为S,那么就相当于S和信息作业的一个最大匹配(这是题目所给贪心原则确定的)。我们考虑二分图最大匹配=二分图最小点覆盖=点数-二分图最大独立集。所以又要求最小,所以这就相当于天数+信息作业数+数学作业数-选择的信息作业数-选择的数学作业数-不同时被信息数学覆盖的天数(这一块可以根据信息数学的选择情况考虑把这些天扔到哪边的最大匹配里)。所以就可以考虑一个dp, f [ i ] [ j [ k ] f[i][j[k] f[i][j[k]表示考虑了左端点<=i的作业,信息最右端点为j,数学最右端点为k,我们考虑i转向i+1时,可以先把每个作业选或不选扔进去转移,然后把这一天选或不选扔进去转移。

方法二:考虑转化为最小割,可以看看我盗的图。首先手玩一下非常正确,然后我们发现这个在割的流程和我们求最大独立集的流程是一致的,所以正确。加上线段树优化建边就比方法一快了。

T2

首先一个常见的结论,这个值一定是任意一条a到b路径再异或若干个环。这是显然的,可以走到一个环上再走回来,会发现只多了一个环的权值,所以可以放肆加环权。手玩发现任意一条a到b的路径都可以,因为任两条可以通过异或环来互化。

考虑维护这个过程,首先看到询问是l到r,就要想到莫队(我没想到QAQ)。考虑显然删边是困难的,所以是回滚莫队。

接下来有一种LCT方法,但是我不会,而且会TLE,所以就只介绍不用LCT的。考虑这个流程,我们是依次加边,如果是两端点不连通,那么合并,否则加入一个环的异或到线性基里。考虑对于每个连通块构建一个可撤销带权并查集(由于一侧回滚一侧只加,所以要可撤销),权值就是当前所在树中,每个点到根(并查集代表元)的路径异或。考虑怎么合并,首先两端点未必是根,所以有一个换根操作,由于xor的性质,这里有一个trick,就是换根相当于每个值都异或上根到新根的路径,这个感性理解一下就懂了。在换根之后,相当于把一个根接到另一个根的儿子,那么我们把这个儿子的连通块所有点异或上这条边即可。上述操作是对于一个块的,用带权并查集可以简单维护。考虑非树边,一个环的权就相当于二点到根的路径异或再异或这个边权,到根异或用并查集查询。最后把环压到线性基里,然后之后都是容易的,不赘述。 O ( n n l o g n ) O(n\sqrt nlogn) O(nn logn)

T3

又是对偶。

以01为二分图,问题是二分图最大匹配=二分图最大独立集,所以就是每行每列选择数字是相同的。若选择0行列是R和C,那么最大独立集为 ∣ R ∣ ∣ C ∣ − S ( R , C ) + S ( R ‾ , C ‾ ) = ∣ R ∣ ∣ C ∣ + S ( U , U ) − S ( R , U ) − S ( U , C ) |R||C|-S(R,C)+S(\overline{R},\overline{C})=|R||C|+S(U,U)-S(R,U)-S(U,C) R∣∣CS(R,C)+S(R,C)=R∣∣C+S(U,U)S(R,U)S(U,C),这里S表示这个子矩阵的1的和。

考虑怎么求,显然的,R一定是选最小的若干行,C一定是选最小的若干列。首先扫描线求出最小若干行若干列的信息,用two-pointer求即可。考虑扩展更强的求法,对于一个固定的|R|,我们知道会逐一加入列,直到加入列的1的个数>|R|,这之后肯定劣(每次加入列新增为|R|-S(新增列))。所以在多次询问中,维护一个线段树,每个位表示|R|为这个时的答案。更新时,相当于一行一列变化。考虑对于行前k小之和数组,一定是一个后缀加,也即线段树后缀加。考虑对于列值<=k的列之和,也显然是一个后缀加。这里有一些细节,要在扫描线的时候顺便算出每个操作是+1还是-1。

NOI模拟赛26

补了一个早上,结果就只猜出T2结论,没救了/kk。

T1

我们考虑这个的一个等价命题,我们把它做成一个排序,然后从左到右删,如果一个数被访问到的时候已经有一个祖先被删了,那么它不删,删k个的概率等价于原问题删k个的概率。

考虑这个的概率为何与原命题等价,这里讲下我假的历程。一开始我的想法和这个类似,但是我是事先剔除了不删的,也就是我相比这个少乘了一个不删元素之间的排列。那么我的有什么问题呢?试着用这个思路和方案数/总方案来算答案,假如我有两种方案,一种是先删x再删其他,总方案数X,一种是先删y再删其他,总方案数Y,我们会发现在计入最后总方案数时,两者之和就是X+Y,那么两者计入总方案数的比重就是X和Y,但是发现原问题,比重应当相同才对(因为在概率上都是1/n),所以出了问题。那么为什么用全排列算就是对的?我们发现这样子算,它们的总方案数都是 ( n − 1 ) ! (n-1)! (n1)!,就一样了。

考虑计数,根据题解思路,一开始自然设计出 f i , j f_{i,j} fi,j表示i的子树中有j个是删的的方案数,发现这样子可以合并,但是很难加入新元素。追本溯源原因就是由于我们不知道这j个最靠后的位置在哪里,但是我们发现如果多记一个最靠后位置,合并时十分奇怪,甚至感觉要一堆容斥啥的,复杂度还不对,说不定还不能优化,总之就是十分奇怪。而我们又要记一个“位置”,又不能记某个代表元素的位置,那么就考虑把状态两维的依赖换一换,记录 f i , j , k f_{i,j,k} fi,j,k,表示i的子树中,排列的前j个元素,有k个删的。这样子发现合并就是两维的卷积,插入新元素也比较容易。虽然感觉这样子定义计数很怪(因为我们没有考虑非前j个的删的的位置(?)),但是仔细思考确实也把答案算出来了。但是复杂度并不对,两维卷积复杂度是 ∑ s z u 2 s z v 2 \sum sz_u^2sz_v^2 szu2szv2,当两个sz都为O(n)的时候这个就算成 O ( n 4 ) O(n^4) O(n4)了,并不能用 ∑ s z u s z v \sum sz_usz_v szuszv时的方法把复杂度算低。

接下来就是另一个我不会的方法了,考虑把一维折进去,然后用差值搞出来。首先想一下折哪维比较好,我们发现j这维在插入新元素转移时,并不是单纯相加操作,不能很好用单纯乘法做。所以把k折进去,具体就是每选入一个删的的时候,就把答案乘上x,然后x从1-n+1枚举,插出一个函数,那么每一项前面的系数就是我们要的值。我好像是第一次见,第一感觉是和wqs二分的方式有一点像。

时间 O ( n 3 ) O(n^3) O(n3),空间 O ( n 2 ) O(n^2) O(n2)

T2

好像有一个O(n)解法,暂且不表(可以去看题解),只写O(nlogn)写法。

首先一个观察得出结论,第一个操作相当于一个指针在环上跑,第二个操作相当于第一个操作+一个交换(先放到第一个位,再一和二交换)。所以就是环上跑跑跑然后换换换。

考虑枚举最后指针位置,那么1都要在指针一边。考虑过去的方式有两种,分为两侧,一侧是所有1向目标位走一步,一侧是一个1移动若干次到目标位(神似复制泡),画了一个图,中间的环表示指针跑的方向。然后我们就可以枚举两个断点 O ( n 2 ) O(n^2) O(n2)

考虑优化,我们知道当指针位置确定时,答案相当于两侧的一个取max,而另一个断点在移动时,适当观察就可以发现两侧答案一个递增一个递减,所以可以二分出两个答案函数的交点(递增函数第一次大于等于递减函数位置),向前取1个和当前分别算一下。

T3

是最简单的,不知道为什么傻傻不会。

这类问题(两类标号,一类情况较少,算贡献)有一种通法(我不会/lh)。可以考虑算出括号序列中((,)),(),)(的个数,然后分别算出排列中每种对应的逆序对数(可以填原排列任意两个),这样子就可以分开计数了。

((和))是容易的,考虑剩下两种,因为相加为定值,算一个即可。()比较难计数(不知道为什么比较难/dx),考虑算)(,我们可以发现,这个一定是伴随()()(这里一对是配对的而不是任意的)出现的,所以计算()(),这个我们发现又可以转化为(()),因为对于两对配对括号,只有包含和配对两种情况。考虑计数(()),这个是容易的。

排列算((和))的两两配对产生的逆序对数是容易的,考虑算()和)(,发现也可以值计数一个,这里哪个都一样,以()为例。最开始可以O(n)算,容易,之后交换时,显然交换的两个是不一样的,考虑这两个和中间的数的贡献的变化,如果原来是(),那么会发现中间的(与)少了贡献,中间的)与(少了贡献,交换位()之间少了贡献,所以中间每个都是少了一个贡献,交换位之间少了一个,一共少了u-v,另一种对应的是多了u-v,所以就可以O(1)处理变化了。

时空复杂度线性。

NOI2023模拟赛27

T1

首先如果是树,那么用组合数随便做。这里的话就是在环上,特别做一下,用 g l , r g_{l,r} gl,r表示环的一侧用了l个,另一侧用了r个,就可以简单 O ( n 2 ) O(n^2) O(n2)做了。

T2

首先一个结论,这个一看就是翻硬币游戏,所以可以套用翻硬币结论(不证),可以把每个硬币看为一个独立子游戏,直接把SG异或一下即可。所以结论是如果当且仅当每个dep都是偶数个棋子,那么后手胜。所以对于每一层用白色表示偶个子,黑色表示奇个子,那么答案就是颜色的段数-1。

考虑怎么算,首先我们搞出O(logn)的LCA和dfn比较。这里我们发现每个点到根的路径可以表示成O(logn)段横着竖着走,所以LCA可以找lcp解决,dfn比较可以找lcp的后一位比较解决。有了这两个就可以直接建虚树算了。

建虚树这里有一个更简单的方法,就是考虑这个图案是分型,所以可以先递归建出下面两个的虚树,再接到上面虚树上,递归构建。

T3

长文警告,话说这是写过的最长题解吧。

我们考虑这个问题就是每次删一个边,然后递归下去形成决策树,问递归最深深度最浅要怎么构造。我们发现可以对于每个边赋一个 [ 1 , n ) [1,n) [1,n)的权值,然后每次在一个连通块里删编号最小的边。这个转化好,把问题从一个有深度,涉及连通块这样抽象东西的问题,转化为了一个可以树形DP贪心的边赋权问题。考虑树形DP,对于每个点x,我们记录一个二进制数,第i位表示存在赋权为i的边,它的端点到x的路上没有比他小的权。那么我们知道,接下来合并的时候不能有两个这样子同时出现,否则矛盾,也可以加入一条小权的边来使它与外断绝。

我们考虑加入x与fax的边的效果,首先一定不在sta里面,然后可以使sta的一位置1,比这位高的置0。我们发现这里出现了一个不太好搞的地方,就是我们是想要让最高位尽量小,但是我们这个操作反而用掉了更加珍贵的低位,可以让数字更小,也就是说感性理解上,原本应当慎重使用小权,而在我们的这个定义下,疯狂的赋原本少见的小权边,反而看起来更优。这不是定义本身问题,而是“看起来”,会影响到我们贪心的思路,原本是没问题的,因为如果疯狂赋小权,必然会导致在上面没法赋小权,所以定义本身是对,但是怪。考虑改一下,把权的定义翻转,先割大的权,这样子的话加边相当于一位置1,然后低位置0,这个就会使数变大了,而目标是使数字较小。

首先我们可以把子树合并问题转化为下述问题:

  • 有若干个数 a i a_i ai,需要构造出一组 b i b_i bi,有 b i ≥ a i b_i\geq a_i biai,使得KaTeX parse error: Undefined control sequence: \or at position 1: \̲o̲r̲ ̲b_i=\sum b_i,这个条件相当于任意两个b的与为0,要minimize ∑ b i \sum b_i bi。(与[ROI2018]无进位加法相同)

考虑这是为什么,我们发现我们加入一条边相当于有一个 b i ≥ a i + 1 b_i\geq a_i+1 biai+1,然后我们这里 b i b_i bi不是任意的,但是上述是任意的。但是我们这里 b i b_i bi可以理解为一种1的数量尽量小的情况,在尽量追求任意两个b的与为0时,这样显然是最好的,所以上述转化虽然变松了,但是最后算出的解,并没有与我们原本的条件发生冲突。

如何解决?首先题解给了一个复杂度较高的贪心。具体就是我们维护最后的和的集合,从高到低位贪心下去,依次判断每一位能否为0。我们考虑如何判断,首先肯定将未处理的低位全部置1,然后从高位到低位扫,有几种情况:(下文 a i a_i ai都已事先+1)

  • 此位为0:如果有一个及以上 a i a_i ai此位是1,那么矛盾。

  • 此位为1:

    • 如果有两个及以上 a i a_i ai此位是1,那么矛盾。
    • 如果有一个 a i a_i ai此位是1,那么显然给这个数,这个数这位变0其余不变,继续过程。
    • 如果没有 a i a_i ai此位是1,那么我们选取最大的一个 a i a_i ai将其删掉。(这里”最大“随便贪或者调整法都能解释)

那么我们用一个线段树或者堆就解决了这一问题,维护sta用bitset。n次合并,判断n次,每次判断扫n个位置,堆和线段树加上bitset维护sta又有nlogn/w,所以复杂度大概是 O ( n 4 l o g n / w ) O(n^4logn/w) O(n4logn/w),会超时。

然后有一种少一个n通过此题的,懒得看,大概就是我们考虑加快比较流程,我们从低到高位基数排序,那么就可以快速排前缀的顺序,而由于每次是整个删或者删后缀,所以我们其实就只用排前缀的顺序,只用线段树等做关于位数的排序,而不是线段树套bitset,大概就会少一个n了。

介绍再少一个n的“无进位加法”原题方法。

考虑算出一个下界情况和上界情况,这里是全填1时的。我们把所有的sta按照从小到大排序,那么显然一个下界是 m a x ( k i + i − 1 ) max(k_i+i-1) max(ki+i1),上界是 m a x ( k i + i ) max(k_i+i) max(ki+i),这里 k i k_i ki表示第i个数的最高位位置,我们可以理解成是一个阶梯形状的东西,然后拿一个斜线去放使得整个阶梯位于斜线下方就是上界,上界下挪一位就是下界。

接下来考虑dfs,我们先得到一个最小的i使得触到了max。然后我们就拿这个来算,首先比i小的都被抵消了,然后i的最高位被减掉了,扔回去继续dfs。我们分析一下复杂度,每次一定只会回溯一次,这是由于取上界dfs下去一定是可行的,不会回溯。这里的回溯条件可以更加苛刻,我们考虑到剩下的数的下界,如果这个下界比 k i k_i ki小了二及以上,那么显然一定不会回溯了,因为取上界就可以把剩下的搞定。然后走向了一个会回溯的分支时,我们全部赋1判断即可。

考虑分析复杂度,我们知道如果走到了会回溯的分支上,那么这个的复杂度一定是 O ( k i ) O(k_i) O(ki)的,所以会回溯的分支的复杂度总共 O ( ∑ k i ) O(\sum k_i) O(ki),而不会回溯的正确分支,每次向下一定至少有一个1被消除了,所以也是 O ( ∑ k i ) O(\sum k_i) O(ki),用线段树和上述基数排序的trick做一下,就是 O ( ∑ k i l o g n ) = O ( n 2 l o g n ) O(\sum k_ilogn)=O(n^2logn) O(kilogn)=O(n2logn)了。

NOI2023模拟赛28

T1

比较难得自己做的题,所以录了一个视频。

视频最后讲错了/cf,怎么可能是min+卷积呢(笑哭),应该是矩阵乘法。。。

还有一个地方可能强调的太少了,就是要对行列分别维护一棵线段树计算答案。

T2

烦死了,看了1h感觉才看懂20%,不看了。。。这种题估计NOI很少出现吧。

T3

T3最简单。。。(虽然我最后一步没想出来就是了)

我们要学会观察subtask,这次里面有一个十分变扭奇怪的n为质数的sub,所以尝试朝着这里想~~(其实这样根本想不出)~~。我是最近线性规划学多了,所以直接尝试转线性规划,然后就是对于每个操作设了一个次数,然后有若干长为k的段操作次数相加要求模m为一个值,然后要求和最小,转完发现和线性规划屁关系没有。但是这样子这题基本就解决了,这样子之后我们当然要尝试解出这个方程,所以我们尝试让变量之间互相表示。然后发现限制相减就得到间隔m的数之间之差有一个关系,所以n为质数就结了,就是固定了一个值所有值都固定,直接枚举。

考虑继续解,这里要告诉自己凡是都要学会尝试,考场我估计直接拼一个k=2一共43pts就跑了,其实56pts也简单的要命,再做一下甚至就A了。56pts就是我们把相互之间有限制关系的放到一起,然后选一个代表元,然后我们把代表元摆到一起,显然可以变成一个段(长为p),然后要求和为一个值,这里我们可以DP来算前p-1个数和模m的值为什么,然后就好了。说的清楚一点就是对于一个段,代表元为x的时候,这个段的和是固定的,可以事先算出来,然后在代表元段中,我们记 f i , j f_{i,j} fi,j表示考虑了前i个元素,和模m为j的最小和,这里就是一个背包,然后i=p-1时,每个j对应的剩下元素取值固定,所以可以直接暴力算出。所以一共 O ( p m 2 ) O(pm^2) O(pm2)

考虑优化我们发现对于同一个段里面的,每个数的函数只有O(1)段,所以考虑合在一起,也即一段的和是一个分为O(n/p)段的函数,每段是一次函数。我们考虑每个一次函数依次去做这个(min,+)卷积,由于是一次函数,这里先不考虑取模,可以从后往前扫原数组,使用单调队列优化,感受一下就是点值加一段就相当于把一次函数平移,所以优劣是固定的(一次函数比另一个高,肯定整段都高),在i处后加入的比前的优,那么i-1也必定优。所以就是 O ( p ∗ m ∗ n / p ) = O ( n m ) O(p*m*n/p)=O(nm) O(pmn/p)=O(nm)

NOI2023模拟赛29

T1

我们从右向左做一个扫描线。可以知道当左端点固定的时候,随着答案与右端点的相关函数是一段段的,斜率依次递减,我们相当于需要一段区间(不合法的还未加入,所以直接是一个前缀)内这些线段的最大值。考虑怎么做这个过程,首先显然是用单调栈去做这个事情,然后考虑在一个线段弹出之时,其实它还是有用的,具体就是左端点>=l的时候的一种可能取值。

我们先对于被弹出的线段做一个维护,它们的左右端点固定,是一个向上的斜线,然后总共O(n)条。考虑查询的时候是前缀最大,所以我们对于右端点r的线段无贡献,不考虑。剩下就是跨过r的线段了,这里暂时我只能想到使用李超树来做。

对于还未弹出的,处理右端点r时一样。处理跨过的时候,可以直接找到对应线段,然后直接计算贡献。

感觉我的做法就是蠢到家了/kk。

题解也不怎么样,对于每个线段分为四种情况考虑,包含,被包含,左边相交,右边相交,前二者可以直接树状数组做,后二者是cdq套李超树,题解说就是两个log,我不太懂。

T2

注意看清数据范围,k是<=1e5的!

这种题理应掌握一种套路,就是用堆啥的来维护,然后一个个加,有点类似超级钢琴,一般这样子然后优化一下就行了。我们考虑来维护这个过程,我们使用dfs,维护一个可重集合,表示当前序列的末尾有哪些,所谓当前序列,长的都一样的。然后考虑大一点的,一定是取出集合最小数x,在原序列加入x右侧的最小最左的数。然后我们依次取这个值的nxt,然后就得到了一串的值,到达了k个就停,否则递归下去,由于最多k个,每取一个都会多一个,所以这里怎么暴力都对(可以对于先算出最小位有哪些,然后双指针依次与集合位置做一对贡献)。然后如果递归下去还不够,那么就回溯,然后取次大,还不够就次次大,这里就是一个区间k大,用主席树做。

T3

感觉又是T3最简单,所以牢记题目难度一定乱序!

我们考虑每次把取的两个向新的连边,那么就成了一个转移的DAG(并没有什么用)。

我们考虑怎么算i的答案,这里我们是做成两两贡献,也就是所求的两倍,可以发现:
a n s i = a n s x i + a n s y i + f x i , u i ∗ s z y i + f y i , v i ∗ s z x i + s z x i ∗ s z y i ∗ w i ans_i=ans_{x_i}+ans_{y_i}+f_{x_i,u_i}*sz_{y_i}+f_{y_i,v_i}*sz_{x_i}+sz_{x_i}*sz_{y_i}*w_i ansi=ansxi+ansyi+fxi,uiszyi+fyi,viszxi+szxiszyiwi
这里 f i , j f_{i,j} fi,j表示编号为i的树中每个点到j的距离和,上述式子分为三部分,分别是两个树内部的答案,两个树到接合处的答案,跨过边的答案。

考虑怎么算f,我们有:
f i , j = f x i , j + ( d i s t ( x i , j , u i ) + w i ) ∗ s z y i + f y i , v i f_{i,j}=f_{x_i,j}+(dist(x_i,j,u_i)+w_i)*sz_{y_i}+f_{y_i,v_i} fi,j=fxi,j+(dist(xi,j,ui)+wi)szyi+fyi,vi
dist表示xi树中的距离,我们这里默认j是在xi树中的,应该也不难理解,就是分开算一下。我们考虑所需的f必然第二维是一个接缝点的映射,从两个式子里就可以看出这一点,所以总共只有 O ( m 2 ) O(m^2) O(m2)个,所以可以直接转移。

考虑怎么算dist,我们有:
d i s t ( i , j , k ) = d i s t ( x i , j , u i ) + w i + d i s t ( y i , v i , k ) dist(i,j,k)=dist(x_i,j,u_i)+w_i+dist(y_i,v_i,k) dist(i,j,k)=dist(xi,j,ui)+wi+dist(yi,vi,k)
这里默认i和j在两个树里,也容易理解。所以我们发现,dist一定是形如 d i s t ( x i , j , u i ) dist(x_i,j,u_i) dist(xi,j,ui) d i s t ( y i , v i , j ) dist(y_i,v_i,j) dist(yi,vi,j),这里j是后继态每个f所可以使用的j的映射,后继有O(m)个,每个后继能用的有O(m)个,第一维有O(m)中取值,所以一共只有 O ( m 3 ) O(m^3) O(m3)个状态。

所以可以三个量一起直接记忆化搜索解决即可, O ( m 3 ) O(m^3) O(m3)

NOI2023模拟赛30

T1

反应了我对于贪心的极度不熟练。

总结一下方法好了:

首先尝试简化问题,处理一些特殊情况,尝试拓展。

然后尝试一些常见方法:借用排序固定顺序(用两个元素比较的局部法),简化状态(如取A之后一定取B,那么可以把A和B合为一个C),分类讨论(分几类分别排序),极端情况/手段(如除非游戏结束否则不取A这样的决策是否优),猜结论(如是否顺序与答案无关),考虑逆序过程(如打怪兽游戏)。对于博弈类问题,还有:转为经典博弈模型,SG打表。

最后确定了一些顺序关系之后,尝试DP或者数据结构来维护。

接下来讲这道题,这个是处理特殊情况->借用排序固定顺序+分类讨论+极端情况/手段->用堆维护。

首先如果都是一张的话那么有一个结论就是两个人肯定都是先取a+b大的。

所以如果上面一张a+b比下面一张大的话,就可以把两张照片分为两堆。

考虑其他情况,我们设第一张的a,b为a,b,第二张的a,b为c,d。

一种是a>=d,b<=c,那么无论A先拿还是后拿,都是优的,又可以知道先拿一定不优,所以B对于这张肯定不会主动出手,而是“跳过”,而A又不能放掉这个机会,所以肯定A第一张,B第二张。

另一种无论B先拿还是后拿,都是优的,处理方法与此类似。

还有一种就是a<=d,b<=c,也就是谁先拿谁倒霉,那么肯定两个人都不要这一堆,直接删了。

T2

这道题的开始思路也挺奇怪的,就是先找到i能拦住j的必要条件depi+ti>=depj+tj,我没有想到。

然后发现这些必要条件构成一个DAG,所以可以直接排序,前面对于后面有阻拦。然后就可以线段树+树剖通过打上一个人来到这里的时间戳解决了(这部分并不是很简单,但是仔细想想就会了(?))。

T3

首先可以知道最大公约数的种类很少。考虑从右向左的扫描线,对于每个左端点维护所有可能的gcd值和个数,可以知道每次gcd减小一次那么一定是除去了某个数,所以左端点在某一位置的gcd的种数是O(logn),那么就可以暴力做了。

考虑下一步,首先一定是二分答案ans,然后计算<=ans的区间个数。同理我们考虑扫描线,我们这里先把所有的数字排开来。然后可以知道对于一个左端点,满足条件的右端点,一定是左端点到所在段的右端点+若干段+某一段的左端点到某个位置。我们考虑分开计算,第一部分的处理显然是朴素的,第二部分的话可以用一个扫描线,算出对于可达右端点包含段i时,左端点位于哪一个区间,这里如果区间如果跨段了,那么就割成几份,可以知道这样子的贡献对数是O(n)的。然后考虑我们有了这些贡献段,形如{l,r,x},那么第二部分显然是好算的,然后也可以顺便算第三部分,肯定是{l,r}为左端点,然后右端点在第x+1段中,这里类欧就呼之欲出了。然后这道题就解决了。

并不会实现类欧/kk。

NOI2023模拟赛31

T1

我们考虑把时间和价值相关的函数画出来,这里相当于每个时间所对应的可以得到的最大价值,也就是说并不是唯一一种操作方案所形成的,会随着横坐标的改变而改变操作方案。

考虑先去掉无用的,也就是使得剩下的满足对于 c x < c y c_xcx<cy v x < v y v_xvx<vy,考虑按照c升序依次加入。找到一个最左的点,使得当前价值已经比c大了,那么为了更优,如果我要加入显然就在这里加入了,这个位置可以二分出来,所以从这里的纵坐标-c,然后画一个斜率v的线去割凸包,单调栈维护就行了。

T2

一眼SGDP。

首先一个O(n^3)的区间DP应该是十分简单的,我们考虑优化这个东西。

我们考虑如果查询全局怎么做,我们可以发现它的后继子游戏状态一定是这样的,除了一个全局的,剩下一定是左端点为i,那么右端点一定是i右侧每种字母第一次出现位置j,或者反过来右端点是i然后左端点是相对意义的j,这里严格规定i!=j,然后只需要(i,j)的状态(注意是开区间,也就是我们用i和j描述区间左右端点,但是对应的局面不包含i和j),也就是说状态数是O(|S|n)的。

考虑优化转移过程,左端点i从右向左扫,取出左端点为i的所有有效区间右端点j,然后枚举下一个取的字母k,我们发现枚举之后,所要求的值是 ( i , s u f i , k ) (i,suf_{i,k}) (i,sufi,k)SG xor 若干两端为k的区间 xor ( p r e j , k , j ) (pre_{j,k},j) (prej,k,j)SG( p r e i , j pre_{i,j} prei,j表示 ≤ i \leq i i的位置中第一次出现j的位置,suf同理,注意这里可以取等),这里如果区间中不包含数,那么SG=0。考虑中间的这个值是可以后缀和的,因为这里肯定是相邻的两个为k的点构成区间,可以边扫边处理后缀和,左右两个SG值可以暴力求。然后算全局的时候枚举一下删的c,然后暴力,一共是O(n|S|^2),足以通过此题。

考虑多次询问怎么办。我们考虑询问一个区间,在确定删的c之后怎样快速计算。我们发现答案是 ( i − 1 , s u f i , k ) (i-1,suf_{i,k}) (i1,sufi,k)SG xor 若干两端为k的区间 xor ( p r e j , k , j + 1 ) (pre_{j,k},j+1) (prej,k,j+1)SG,这同样可以O(1)快速计算。

总共O(n|S|^2+q|S|)

T3

这个是contest912贪心专题的最后一题,就是个难死人的构造,这里不再赘述,可以移步专题区看题解。

NOI2023模拟赛32

T1

这题比较edu。

我们考虑对于每个右端点,求出每个位置是由谁控制的,每个人都想控制较高位,这里就可以用一个bitset多记一个每位是谁。加入x的时候,我们从高到低位走,如果遇到了一个,那么比较x和它谁的优先级高(也即谁靠右),然后优先级高的放在bitset里,优先级低的拿来继续向低位加,总共就O(nlogn)了。然后询问的时候只要从高到低贪心即可。操作一对于预处理的东西没有影响,这个东西只有询问的时候需要调用,处理极度朴素。

T2

这题也比较edu,有一个对偶O(nlog^2n)做法,我写在对偶学习笔记里了。

这里写一个O(nlogn)的做法。我们考虑DP,用 f i f_i fi表示第i子树中,没有继续向上延伸的邻域的最大美丽度和。考虑转移,我们对于每朵花j,算出它深度最浅的邻域位置i,那么在计算 f i f_i fi的时候,就可以选j和一些其他的,或者不选直接从 ∑ f s o n \sum f_{son} fson转移过来。后者是简单的,考虑前者。我们发现这个东西中所谓的其他,其实就是 ∑ f k \sum f_k fk其中k与j恰好不在j的邻域中,也就是和j的距离为 r j + 1 r_j+1 rj+1的点。我们考虑使用点分树/边分树,支持单点加和这种查询,这个是经典问题,不赘述,发现瓶颈在求dist,再用O(nlogn)-O(1)LCA,这题时间复杂度就是O(nlogn)了。

T3

NOI2023模拟赛33

T1

T2

NOI2023模拟赛41

T1

我们设计函数 p ( x ) p(x) p(x)表示x质因子分解后各项的和,然后随便推一下就有 d ( x , y ) = p ( x ) + p ( y ) − 2 p ( g c d ( x , y ) ) d(x,y)=p(x)+p(y)-2p(gcd(x,y)) d(x,y)=p(x)+p(y)2p(gcd(x,y))

所以答案就是:
2 a n s = ∑ i = 1 n ∑ j = 1 n ( p ( i ) + p ( j ) − 2 p ( g c d ( i , j ) ) ) = 2 n ∑ i = 1 n p ( i ) − 2 ∑ i = 1 n ∑ j = 1 n p ( g c d ( i , j ) ) 2ans=\sum_{i=1}^n\sum_{j=1}^n(p(i)+p(j)-2p(gcd(i,j)))\\ =2n\sum_{i=1}^np(i)-2\sum_{i=1}^n\sum_{j=1}^np(gcd(i,j)) 2ans=i=1nj=1n(p(i)+p(j)2p(gcd(i,j)))=2ni=1np(i)2i=1nj=1np(gcd(i,j))
我们分开计算,对于第一部分,有:
S ( n ) = ∑ i = 1 n p ( i ) S ( n ) = ∑ i ∈ 质数 , i < = n S ( ⌊ n p ⌋ ) + ⌊ n p ⌋ p = ∑ l , r S ( ⌊ n l ⌋ ) + ⌊ n l ⌋ ( S p ( r ) − S p ( l − 1 ) )    这一步是整除分块, S p 是质数和 S(n)=\sum_{i=1}^np(i)\\ S(n)=\sum_{i\in质数,i<=n}S(\lfloor\frac{n}{p}\rfloor)+\lfloor\frac{n}{p}\rfloor p\\ =\sum_{l,r}S(\lfloor\frac{n}{l}\rfloor)+\lfloor\frac{n}{l}\rfloor (S_p(r)-S_p(l-1))\ \ \ 这一步是整除分块,S_p是质数和 S(n)=i=1np(i)S(n)=i质数,i<=nS(⌊pn⌋)+pnp=l,rS(⌊ln⌋)+ln(Sp(r)Sp(l1))   这一步是整除分块,Sp是质数和
这里 S p S_p Sp是可以min25筛的,然后这里就类似杜教筛做就好了。

对于第二部分,有:
S 2 ( n ) = ∑ i = 1 n ∑ j = 1 n p ( g c d ( i , j ) ) S 2 ( n ) = ∑ g = 1 n p ( g ) ∑ d = 1 ⌊ n g ⌋ μ ( d ) ⌊ n g d ⌋ ⌊ n g d ⌋ = ∑ g = 1 n ⌊ n g ⌋ ⌊ n g ⌋ ∑ d ∣ g μ ( d ) p ( g d ) = ∑ g = 1 n ⌊ n g ⌋ 2 ( ∑ d ∣ g μ ( d ) ∗ p ( g ) − ∑ d ∣ g μ ( d ) p ( d ) ) = ∑ g = 1 n ⌊ n g ⌋ 2 ( [ g = = 1 ] p ( g ) − ∑ d ∣ g μ ( d ) p ( d ) ) = − ∑ g = 1 n ⌊ n g ⌋ 2 ∑ d ∣ g μ ( d ) p ( d ) S2(n)=\sum_{i=1}^n\sum_{j=1}^np(gcd(i,j))\\ S2(n)=\sum_{g=1}^np(g)\sum_{d=1}^{\lfloor\frac{n}{g}\rfloor}\mu(d)\lfloor\frac{n}{gd}\rfloor\lfloor\frac{n}{gd}\rfloor\\ =\sum_{g=1}^n\lfloor\frac{n}{g}\rfloor\lfloor\frac{n}{g}\rfloor\sum_{d|g}\mu(d)p(\frac{g}{d})\\ =\sum_{g=1}^n\lfloor\frac{n}{g}\rfloor^2(\sum_{d|g}\mu(d)*p(g)-\sum_{d|g}\mu(d)p(d))\\ =\sum_{g=1}^n\lfloor\frac{n}{g}\rfloor^2([g==1]p(g)-\sum_{d|g}\mu(d)p(d))\\ =-\sum_{g=1}^n\lfloor\frac{n}{g}\rfloor^2\sum_{d|g}\mu(d)p(d) S2(n)=i=1nj=1np(gcd(i,j))S2(n)=g=1np(g)d=1gnμ(d)gdngdn=g=1ngngndgμ(d)p(dg)=g=1ngn2(dgμ(d)p(g)dgμ(d)p(d))=g=1ngn2([g==1]p(g)dgμ(d)p(d))=g=1ngn2dgμ(d)p(d)
我们考虑如何计算后面的一个sigma的东西,显然我们知道d一定是形如 p 1 0 / 1 p 2 0 / 1 ⋯ p_1^{0/1}p_2^{0/1}\cdots p10/1p20/1,否则 μ \mu μ的值是0。考虑 p ( p 1 ) p(p_1) p(p1)前面的系数是多少,也即 ∑ i 2 , ⋯ μ ( p 1 p 2 i 2 ⋯   ) \sum_{i2,\cdots}\mu(p_1p_2^{i_2}\cdots) i2,μ(p1p2i2),那么就等于 − ( 1 + ( − 1 ) ) ( 1 + ( − 1 ) ) ⋯ -(1+(-1))(1+(-1))\cdots (1+(1))(1+(1))的展开式,所以值是0,所以说明系数是0,所以整个sigma的值就是0。到了这里,就不得不说一些坑,就是 0 0 = 1 0^0=1 00=1这件事,这是做题万不可忘的,也就是此处d为质数时,sigma是有值的,就是 1 − p 1-p 1p

所以有:
S 2 ( n ) = ∑ g = 1 & g ∈ 质数 n ⌊ n g ⌋ 2 ( g − 1 ) = ∑ l , r ⌊ n l ⌋ 2 ( ( S p ( r ) − S p ( l − 1 ) ) − ( C p ( r ) − C p ( l − 1 ) ) )     C p 表示质数数量 S2(n)=\sum_{g=1\&g\in质数}^n\lfloor\frac{n}{g}\rfloor^2(g-1)\\ =\sum_{l,r}\lfloor\frac{n}{l}\rfloor^2((S_p(r)-S_p(l-1))-(C_p(r)-C_p(l-1)))\ \ \ C_p表示质数数量 S2(n)=g=1&g质数ngn2(g1)=l,rln2((Sp(r)Sp(l1))(Cp(r)Cp(l1)))   Cp表示质数数量
这个同理可以杜教筛。

2023杭电多校

就只是写一下考场想出来的(大部分码不出/dk),和一些比较妙的不会题。

2023“钉耙编程”中国大学生算法设计超级联赛(1)

1001

要相信我的速度!!!

就是把路径抽离出来然后对每个点做一个EXCRT。

1002

sb树形DP

1003

发现自己爆标了!大概优了一个n!

区间DP,这里想到了一个复杂度相对较优的(大概劣一点也能过)。

我们先设计一个最简单的DP状态,就是 f [ l ] [ r ] f[l][r] f[l][r]表示l到r合成一个的最大收益。我们发现现在还要合几个,就相当于是一个序列,然后其中挖空几段作为f计入贡献,然后剩下的都是一种颜色直接计入答案。我们考虑怎么计算这一部分,我们可以设计状态 g [ l ] [ r ] [ i ] g[l][r][i] g[l][r][i],表示l和r未合过,然后其中包括l和r一共有i个点可以合,剩下的点用f数组合了的答案最大值,发现这个转移是朴素的,每次只考虑枚举中转点然后i转移向i+1,然后就直接 O ( n 4 ) O(n^4) O(n4),已经爆标了qwq。

但是复杂度可以进一步优化,考虑此题性质是 2 i 2^i 2i个合并在一起,所以考虑设计状态为 g [ l ] [ r ] [ i ] g[l][r][i] g[l][r][i],表示包括l和r有 2 i 2^i 2i个值,然后我们发现由两个i转移向i+1的时候接头处被吃掉了一个,所以相当于两个 2 i 2^i 2i的g转移向了 2 i + 1 − 1 2^{i+1}-1 2i+11,所以新增数组 h [ l ] [ r ] [ i ] h[l][r][i] h[l][r][i],表示包括l和r有 2 i − 1 2^i-1 2i1个值,然后每次我们由g[i]+g[i]转移向h[i+1],再h[i]+f转移向g[i],再g[i]转移向f(表示用掉这些来合成然后卖),所以一共复杂度 O ( n 3 l o g n ) O(n^3logn) O(n3logn),不知道比标算那个 O ( n 2 m 2 R 2 ) O(n^2m^2R^2) O(n2m2R2)好多少/dx。

1004

计几不会。

1005

用Lyndon或者SA就好了。

1006

就是一个可持久化单调队列的斜率优化。

如果要算出每个点的答案,可以从叶子向上用李超线段树维护凸包同时用线段树合并继承儿子。

1007

我们设计一个k元形式幂级数 G ( x 1 , ⋯   , x k ) = ∑ i 1 , ⋅ , i k c i 1 , ⋯   , i k x 1 i 1 ⋯ x k i k G(x_1,\cdots,x_k)=\sum_{i_1,\cdot,i_k} c_{i_1,\cdots,i_k}x_1^{i_1}\cdots x_k^{i_k} G(x1,,xk)=i1,,ikci1,,ikx1i1xkik

c表示这个向量出现次数。

我们要的是 F = 1 + G + G 2 + ⋯ = 1 1 − G F=1+G+G^2+\cdots=\frac{1}{1-G} F=1+G+G2+=1G1,也即一个形式幂级数的组合。

对于有障碍的我们就再算一个 f i f_i fi表示走到第i个障碍的方案,然后容斥一下即可。

接下来考虑k元形式幂级数的卷积。

这里就是EI的维数爆炸解法(cmdblog里面有),我们直接把所有维用变进制数压在一起,为了避免进位问题,我们引入占位函数 x ( i ) = ⌊ i n 1 ⌋ + ⌊ i n 1 × n 2 ⌋ + ⋯ x(i)=\lfloor\frac{i}{n_1}\rfloor+\lfloor\frac{i}{n_1\times n_2}\rfloor+\cdots x(i)=n1i+n1×n2i+,发现 x ( i ) + x ( j ) = x ( i + j ) x(i)+x(j)=x(i+j) x(i)+x(j)=x(i+j)当且仅当没有进位,考虑 x ( i + j ) − x ( i ) − x ( j ) ∈ ( 0 , 1 ) x(i+j)-x(i)-x(j)\in(0,1) x(i+j)x(i)x(j)(0,1),所以总的 ∏ i = 1 k n i \prod_{i=1}^k n_i i=1kni下取整必为0),所以可以在模 t k − 1 t^k-1 tk1意义下循环卷积就有所有情况了。然后可以在第一维DFT后,循环卷积,再IDFT回去,由于k

1008

我们可以发现加体力道具收益和休息一样,加速度道具和训练一样。

所以我们发现只要有体力就锻炼,没体力就休息是最优的。

如果n为偶数,那么答案就是(n+2)/2*15。

如果n为奇数,第一次我们考虑race,然后有尽量购买一个50体力药或者两个25体力药,然后就相当于将多的一个回合转换为了50个商店币,然后尽量去买7speed药或两个3speed药,然后分情况算下概率就好了。

1009

sb容斥。

1010

考虑如果比x小了那么永远比x小,所以每个点从比x大到小于等于x只有一个转折点,就是两棵线段树,一棵维护小于等于当前x的,一棵维护大于x的,然后随便搞搞就好了。

1011

发现可以分块,然后在每个块中开一个平衡树。

对于整块,由于变大的只会变大,所以这部分一个加操作即可,剩下部分是区间翻转+加操作。

对于散块,可以暴力重构,但是有更加好的方法。我们考虑抽离出未修改位置,小于x的修改位置,大于等于x的修改位置,然后三个有序序列合并就是线性的了。

平均一下是 O ( n n l o g n ) O(n\sqrt{nlogn}) O(nnlogn )

1012

考虑SG函数,有 S G ( u ) = ( S G ( v 1 ) + 1 ) x o r ( S G ( v 2 ) + 1 ) x o r ⋯ ( S G ( v l ) + 1 ) SG(u)=(SG(v_1)+1)xor(SG(v_2)+1)xor\cdots(SG(v_l)+1) SG(u)=(SG(v1)+1)xor(SG(v2)+1)xor(SG(vl)+1)

在换根时,考虑有 a n s ( v ) = S G ( v ) x o r ( a n s ( u ) x o r ( S G ( v ) + 1 ) + 1 ) ans(v)=SG(v)xor(ans(u)xor(SG(v)+1)+1) ans(v)=SG(v)xor(ans(u)xor(SG(v)+1)+1)

所以 A N S = ∑ [ a n s ( u ) > 0 ] / n ANS=\sum[ans(u)>0]/n ANS=[ans(u)>0]/n

2023“钉耙编程”中国大学生算法设计超级联赛(2)

1001

求出sg函数后发现有一个4k+2的循环节,猜下结论就好了。证明看题解。

1002

每次是从高到低把一段连续0变为1,考虑特殊情况n=1,和贪完剩余操作为奇次时可能将最低位翻为0。

1003

圆方树,题目太长不想看了。

看了一下题解就是有一个trick,考虑能否通过割一个点使得一些关键点两两不连通。一种方法是找出三个点的中心(将它们分开的割点),那么只有可能是这个,试下即可。一种方法是建出圆方树上虚树,如果是菊花且中心是圆点,那么可以。

1004

我们考虑找递推式。我们在剩下n个位时,可以在最后一个放1个,然后剩下显然 f n − 1 f_{n-1} fn1是一个下界(相当于有一个位不能用了,也就是当前还堆着其他牌的初始堆不能塞东西进去,所以不能用了),然后剩的n-1个位依次类推,所以就是 f n = ∑ i = 1 n − 1 ( f i + 1 ) f_n=\sum_{i=1}^{n-1}(f_i+1) fn=i=1n1(fi+1),然后打出表,发现就是 f n = 2 n − 1 − 1 f_n=2^{n-1}-1 fn=2n11。仔细的证还是移步题解吧。

1005

考虑从右到左扫描线,对于每个左端点,求出一个最小的右端点,使得这个区间的值第k位为1。我们考虑值相当于 s r − s l + a l = s r − ( s l − a l ) s_r-s_l+a_l=s_r-(s_l-a_l) srsl+al=sr(slal)。有两种情况,一种是 s l − a l ≥ 0 s_l-a_l\geq0 slal0,此时我们发现这相当于询问两个数相减的第k位,可以在模 2 k + 1 2^{k+1} 2k+1次之后,对于x-y,如果x第k位为1,y第k位为1,且前者前k-1位小于后者,或y第k位为0,且前者前k-1位大于等于后者,如果x第k位为0,类似讨论一下即可。另一种情况 s l − a l < 0 s_l-a_l<0 slal<0,此时相当于一个x+y的第k位,也是类似讨论一下即可。时间O(nlogn)。

1006

计算几何也要适当会嘛。我们对于两两点,考虑所有点是否都在这个有向边的左侧,如果是就连边。最后用floyd跑一边最小环即可。

1007

就是一个bitset优化暴力,有一个细节就是u伸出的两个点中不能有v。

1008

就是一个线段树套矩阵,要仔细审是子序列而不是子串。

如果改问子串,最好写自动机上DP,否则很容易挂(考场写子串就挂了)。

1009

签到题。

1010

可以写线段树优化建图费用流。

题解的做法复杂度更为科学,是考虑dp, d p [ i ] [ j ] dp[i][j] dp[i][j]表示最后两个人在i和j的最小花费,我们考虑到把这个转移到 d p [ j ] [ k ] dp[j][k] dp[j][k],发现只要满足 i + m ≥ k i+m\geq k i+mk 即可,所以就是一个后缀最小值。j表示比i大多少,i在模m意义下滚动,空间就是O(m^2),时间O(nm)。

1011

我们考虑计算 f ( n , k ) = ∑ i = k + 1 n 1 n × ( p 1 − p i − 1 的最大值在 [ 1 , k ] 的概率 ) f(n,k)=\sum\limits_{i=k+1}^n\frac{1}{n}\times(p_1-p_{i-1}的最大值在[1,k]的概率) f(n,k)=i=k+1nn1×(p1pi1的最大值在[1,k]的概率),前面的1/n是最大值位于i的概率。所以 f ( n , k ) = ∑ 1 n × k i − 1 = k n ∑ i = k n − 1 1 i f(n,k)=\sum\frac{1}{n}\times \frac{k}{i-1}=\frac{k}{n}\sum_{i=k}^{n-1}\frac{1}{i} f(n,k)=n1×i1k=nki=kn1i1,可以直接暴力,可以三分,可以求导出k=n/e最大,然后枚举上下30个(这题1个就行了)。

1012

我们就朴素的建网络流图,每个点都一分为二来限制上界。然后每次涉及到的两个点我们建出新的,剩下重复利用,对于每次的两个我们连边 x → y ′ x\rightarrow y^{'} xy y → x ′ y\rightarrow x^{'} yx,流量为1即可。最后一遍最大流。

1013

计几+多项式,不会。

2023“钉耙编程”中国大学生算法设计超级联赛(3)

1001

1002

六维偏序(K表示维数),被吓到了。

我直接一个百度,得到在六维偏序计算逆序对的时候,可以对每一维开n个bitset,然后对于每个数,我们把比他小的数的bitset(预处理每维前缀对应的bitset)拿来&一下然后count就好了。但是空间会爆,所以我们分块(长度B),然后每次一个块和剩下数计算,还有一个块内计算,这样的话每次bitset等数组只用开根号个长度根号的,且复杂度未变。

说了这么多,这题并没有解决。

我们手写bitset!我们对于每个二进制压位数(压C位)(对应包含的i集合不同),处理出来我可以拿的为sta时的最大值,这里的时间复杂度是 O ( n B B C 2 C ) = O ( n 2 C C ) O(\frac{n}{B}\frac{B}{C}2^C)=O(\frac{n2^C}{C}) O(BnCB2C)=O(Cn2C),我们剩下就和上面是一样的,就是 O ( K n B n B C ) = O ( K n 2 C ) O(K\frac{n}{B}n\frac{B}{C})=O(\frac{Kn^2}{C}) O(KBnnCB)=O(CKn2)。我们手玩/尝试得出C=17是比较优的,可以通过此题。

感觉挺有教育意义的。

1003

1004

其实就是暴力,我们对于1和每个i配对,然后得到一组,我们拿来验证一下,具体就是看看(xj+dx,yj+dy)和(xj-dx,yj-dy)是否有其中一者,有就可能可以配对,又全部随机所以产生矛盾的概率很小。如果dx!=0||dy!=0,那么-dx和-dy也是一组解,否则记一次。考虑几个极端情况,当只有两个的时候,也就是一个斜线,那么我们可能会搞出一个121的东西(也就是有一个位置重了),那么处理不好会出现重复的解,所以要去重。还有一个就是1点坐标和i点重了,那么我们会拿(0,0)来试,但是如果像我一样用set来维护哪里有值,就可能出现自己和自己配对,那么就一定会判为合法,就假了,所以要用map,如果dx=dy=0,要在去掉自己后再判。

1005

先离散,考虑DP,用 f i , j f_{i,j} fi,j表示一共i个数,最大值是j的方案数,转移j不变的时候判一下有没有多的数可以用,j变的时候用一个前缀和优化即可。

1006

1007

1008

1009

1010

由于随机,所以有一个结论就是如果用段来维护可达位置,那么只有O(1)个段。所以就可以直接线段树维护这个,暴力两两做,然后把重叠的合并,复杂度就是O(nlogn)了。

考虑感性理解这个结论。非常感性的证明是我们由于是随机,所以不妨假设都在三等分点,然后算一下就只有一段就好了(虽然看起来很假,但常常可以帮我们找结论,考场感性证明)。一个相对理性的证明是首先对于n个取i个形成的段不难理解成O(1)(这个比较显然?),然后考虑不同i之间的,如果i与i+1之间不重叠,那么有最大的i个r之和小于最小的i+1个l之和,由于随机分布,所以r-l可以理解成O(n)的(这个可以算期望),而l也是O(n)级别,所以就是i个O(n)之和小于O(n),显然这个概率在i不断变大的时候概率越来越小,所以概率之和感觉上就是一个快速收敛的东西,同时显然O(lnn)就是一个级松的上界了(可以把i个O(n)之和从类似二项式分布(不会概率/kk)看成一个均匀分布的来算就是O(nlnn)),作为复杂度也可以过题了。

1011

我们考虑每个新格子是由哪些和过来的,然后暴力判一下这些是否都一样就好了,n很小,怎么暴力都行。

1012

这道题比较有意思,我的map套map再次出山了,这次更加厉害,有一维是pair的,另一维我还暴力做了前缀和/dx。

我们考虑怎么做,首先一对数a,b,有a>b,那么一定是由a-b,b转移过来的,然后用辗转相除法的过程,那么就是一维固定为b,另一维为a-kb这样子的等差数列,形如这样的等差数列有nlogn个。我们以一维的值,和另一维等差数列的首项为代表元存储这个等差序列(考虑等差序列公差就是另一维的值)(考虑首项一定是a%b,因为不然的话a还是比b大可以继续减)。对于每个代表元开一个map维护a-kb中的k,所以就有了一个map套map。考虑一下如果可以由A,B转移过来的话,以A>=B为例,那么一定是B和A%B为代表元且k>=A/B,可以总的前去比A/B小的最大一个对应的前缀和,这里发现A,B不可能在两个等差数列所以两对数不会对它重复贡献,我们A>=B算一次再abABswap后A>=B算一次刚好包含所有情况。这里漏了一个情况就是a==b的时候,我们发现只可能是A0或0A转移过来,又A和B不为0,所以只可能a=b=A=B,特殊处理一下就好。

2023“钉耙编程”中国大学生算法设计超级联赛(4)

1001

1002

考虑子树内怎么做,可以线段树合并+线段树二分。(注意,牢记线段树二分这个trick,不要突然失忆)考虑子树外怎么做,我们在线段树里面维护有删除的点的答案,然后分开两部分计算,一个是有删除的部分的max,一个是没删除的部分的max。前面这个就是这种特殊线段树的特殊合并(相当于维护了tot-x,所以合并后还要减tot,也即tot-x+tot-y-tot=tot-x-y),以及线段树二分。后面这个可以树形dp,朴素但是细节多。一种更好的方法是构建一个可持久化的整树,然后在残树线段树合并的时候一起合并。具体就是如果残树return了,那么整树也可以直接继承对应的点的信息然后return,儿子处特殊处理,由于操作次数和残树一样,所以复杂度对。

1003

简单双指针扫一下即可。

1004

考虑每个点的概率是独立的,可以分别计算再相加就是期望。所以答案就是n*单点概率。考虑计算后者,我们用一个二重的东西来转移,一个表示k次后,在原位的概率,一个表示不再原位的概率,然后就可以矩快快速转移了。

1005

不难,但是细节多。

1006

简单题。

1007

使用mobius反演,有 l n   n = ∑ d ∣ n S ( d ) ln\ n=\sum_{d|n} S(d) ln n=dnS(d),所以 n = ∏ d ∣ n a n s ( d ) n=\prod_{d|n} ans(d) n=dnans(d),那么我们先考虑d是1,所以ans(1)=1,然后有ans§=p,然后有ans(p^k)=p,然后有ans(p1p2……)=0。就可以mr快速计算了。

1008

考虑莫反之后的式子,我们枚举的d一定是i的因子。接下来考虑fail树上dp,维护一个桶,第i位表示这个点到根路径上满足 j = k i j=ki j=ki的权值和。考虑复杂度,加入一个点,要在对应因子位加,那么是 n / 1 + n / 2 + ⋯ = O ( n l n n ) n/1+n/2+\cdots=O(nlnn) n/1+n/2+=O(nlnn),查询类似分析。

1009

该式子就是 ∑ / ( n k ) \sum/\tbinom{n}{k} /(kn)。先考虑k=2的情况,依次考虑每条边(u,v),那么我们先对于每个点求出来 f x f_x fx表示x子树内,去掉颜色为 c ( f a x , x ) c(fa_x,x) c(fax,x)的对应子树之后有多少个点,这个可以让每个点对第一个出现相同颜色的祖先做一次贡献来计算。要跨过(u,v),所以一个端点的可取点数就是 f u f_u fu,另一个端点,考虑如果有一个祖先颜色和这个边一样,那么就是 f p f_p fp,否则是根节点去掉颜色c的子树,这个也是可以预处理的。k>2的时候其他点任选,多乘 ( n − 2 k − 2 ) \tbinom{n-2}{k-2} (k2n2)即可。

1010

简单结论题。

1011

简单题,注意thick twice,code once,尽量用方便的写法。

1012

简单排序题。

2023“钉耙编程”中国大学生算法设计超级联赛(5)

1001

考虑每个点和每个线段计算一个值。这里教会了我一件事,就是为了保证精度,绝对不要有一个intmax的东西平方又开根,这样子小数位绝对挂。为了精度尽量正确,由于要保证小数位,而开根是整数位和小数位分开开根的,又是优先保证整数位精度,那么很有可能会出现整数位有16位,那么小数位准的只有2位了,那么开根的时候,如果要保留4位,我们需要精确的就是8位,那么很可能爆精。所以最好解决方法是尽量把开根变成除法。这里就是我把垂点在线段上时的情况,改点积+勾股,变成了叉积就好了。

1002

推一下发现 g c d ( 2 a − 1 , 2 b − 1 ) = 2 g c d ( a , b ) − 1 gcd(2^a-1,2^b-1)=2^{gcd(a,b)}-1 gcd(2a1,2b1)=2gcd(a,b)1,就随便推一下莫反,最后式子把k用二项式展开,就是要求 i d p ∗ μ id_p*\mu idpμ的块筛,那么我们就发现 i d p ∗ μ ∗ I = ∑ i d p id_p*\mu*I=\sum id_p idpμI=idp,所以可以杜教筛。

1003

我是直接写1004的。

1004

考虑回文串只有O(n)种,先暴力PAM一次求出有哪几种回文串,然后hash暴力判哪些是双回文串,然后再跑一遍PAM,算出PAM树每个节点到根一段路上有几个双回文串。于是就解决了。

1005

可以使用生成函数,但是不熟。

我们考虑最后计算方案数的时候,我们给每组一个标号,然后用插板来划分组,然后发现标号去掉是 1 m ! \frac{1}{m!} m!1,然后点随机撒进去是 n ! n! n!的,所以变成插板,每个板距离是 [ 1 , k ] [1,k] [1,k]的,可以容斥几个位置不满足解决。

1006

简单DP。

1007

考虑要计算的是 ( p x + 1 − p ) n (px+1-p)^n (px+1p)n的第k项乘上 s k s_k sk,这是简单的。 i m i^m im的处理可以欧拉筛O(n)。

1008

我们考虑对于 ∑ i = 0 n i m = ∑ i = 0 m a i n i ‾ \sum\limits_{i=0}^n i^m=\sum\limits_{i=0}^m a_in^{\underline{i}} i=0nim=i=0maini

考虑怎么做我们分成两步,第一步把 ∑ i = 0 n i m \sum\limits_{i=0}^n i^m i=0nim变成一个m次多项式,第二步用第二类斯特林数。第二步是简单的,考虑第一步,我们发现拉插并不管用,所以使用NTT,我们发现NTT所需的若干点值带入时,我们可以使用等比数列求和快速做,然后IDFT回去就好了。

然后我们有
a n s = ∑ i = 0 n ( n i ) p i ( 1 − p ) n − i ∑ j = 0 m a j i j ‾ = ∑ j = 0 m a j j ! ∑ i = 0 n ( n i ) ( i j ) p i ( 1 − p ) n − i = ∑ j = 0 m a j j ! ( n j ) p j ∑ i = j n ( n − j i − j ) p i − j ( 1 − p ) n − i = ∑ j = 0 m a j j ! ( n j ) p j ans=\sum\limits_{i=0}^n\tbinom{n}{i}p^i(1-p)^{n-i}\sum\limits_{j=0}^ma_ji^{\underline{j}}\\ =\sum\limits_{j=0}^ma_jj!\sum\limits_{i=0}^n\tbinom{n}{i}\tbinom{i}{j}p^i(1-p)^{n-i}\\ =\sum\limits_{j=0}^ma_jj!\tbinom{n}{j}p^j\sum\limits_{i=j}^n\tbinom{n-j}{i-j}p^{i-j}(1-p)^{n-i}\\ =\sum\limits_{j=0}^ma_jj!\tbinom{n}{j}p^j ans=i=0n(in)pi(1p)nij=0majij=j=0majj!i=0n(in)(ji)pi(1p)ni=j=0majj!(jn)pji=jn(ijnj)pij(1p)ni=j=0majj!(jn)pj
于是就好了。

1009

简单题,注意题目有没有给出父亲标号比儿子小。

1010

相当于两个问题,一个是子树选两个数xor最大值,一个是去掉一个子树选两个数xor最大值。第一个可以字典树+启发式合并2log,第二个可以先找到对于整棵树xor最大的两个位置,那么答案不是它们xor的,一定是包含了其中的一个,具体就是在它们到根的路径并上,由于是两条路,可以直接字典树暴力加点,每个点只会加一次。

1011

考虑割边显然不能断,取一个min。仙人掌的话显然时刻有n-1个边是充要的,那么就是 m i n ( w 1 + w 2 , w 3 ) min(w1+w2,w3) min(w1+w2,w3),其中 w i w_i wi是第i小。

1012

简单题。

2023“钉耙编程”中国大学生算法设计超级联赛(6)

1001

就是border转周期后直接快速幂。

1002

我们可以暴力扫,然后暴力加入,用树状数组维护,考虑只有 O ( n ) O(\sqrt n) O(n )对,所以是对的。

因为只有 O ( n n ) O(n\sqrt n) O(nn )次加入, O ( n ) O(n) O(n)次查询,所以可以值域分块来平衡复杂度去掉logn。

1003

我是用单纯形板子的,std不想了解。

1004

我们算出三种颜色个数x,y,z,我们把x-=z,y-=z,那么条件等价于x=y=0,用点分治+map解决即可。

1005

我们考虑可以求出以每个点为左上端点的最大的L,然后考虑就是若干i从1-L变,然后左上端点固定,所以矩阵查询改成前缀和的差分,通过对一行,一列,一对角线打标记来得到对于每个前缀和的贡献,然后发现是加上一个等差数列,可以二次差分。

1006

我们考虑对于每个点算出跨过它的区间在它的不同取值下,分别有多少个,我们可以枚举每个点,然后枚举跨过它的区间[l,r],我们计算出所有的 s r − s l − 1 − a i s_r-s_{l-1}-a_i srsl1ai,然后放到桶里面,然后我们枚举i的取值,枚举合成的平方值,然后在桶里面查,一共 O ( n 3 ) O(n^3) O(n3)

1007

二分套数据/cf/cf/cf。暴力过/cf/cf/cf。

1008

被坑了,对于一些题目,可能SG是不好做的,维护必胜必败是好做的。这里我们就像every SG那样,算出必胜必败和值,然后我们一起做,对每个左右端点和必胜必败开一个单调队列维护值,然后直接转移即可。

1009

1010

倍增算即可。

1011

2023“钉耙编程”中国大学生算法设计超级联赛(7)

1001

我们考虑由于有断边和另一种操作,所以不可以直接时间倒流。

所以考虑直接断边,这里有一种类似启发式的方式。

考虑对于每一个连通块维护一个线段树维护每种颜色的次数,和一个并查集维护每种颜色变成了什么。考虑二操作,就可以暴力在对应的线段树里面抽出含有的颜色,同时在线段树里面把这块清了(ls和rs归0),之后线段树上单点加,并查集暴力连。对于三操作,暴力查询。对于一操作,考虑启发式,暴力查出小块每个点的信息,在大块的线段树和并查集上把小块信息去了,同时构建小块线段树和并查集。一共 O ( n l o g 2 n + m l o g n ) O(nlog^2n+mlogn) O(nlog2n+mlogn)

1002

结论简单,就是一旦有>1的,答案就是499122177,否则是0或1。

1003

考虑(1234),(1235)生成S5,同理的,S7,S8也可以生成,所以用并查集维护置换,如果大小不是4或6,那就是任意置换,否则如果是4,那么是(1234)生成的群,如果是6,那么就是(1234),(3456)生成的群,直接做。

1004

可以构造类似131313221313132的,然后发现与暴力打表的前几项是符合的,然后说明这种构造是合理的。

1005

我们考虑对于当前串,尝试加入’a’-‘z’,我们同时维护当前subsequence和substring的最左的末尾x和y。考虑如何尝试,我们可以得到x’和y’(实现的时候存的是sam上的节点,但是可以对于每个sam节点得出最靠左的位置),如果不存在y’,那么久直接加入这个然后输出答案即可。如果存在那么我们考虑,如果有x‘!=y’,那么我们之后把x’之后的全选就是一种合法方案,直接递归下去。否则,首先,我们一定在x’之后选尽量多元素,假设后面有p个,那么就选p-1个。接下来考虑两种情况,如果当前字符串不是同一个字符,那么我们发现用位置靠后的substring是无效的,因为长度都不够了,然后我们接下来x’之后选最后p-1个,那么相当于如果非法,那么x’的后面有一个长度p-1的border,所以就是x’后面字符全部相同,这显然是紧的界。如果当前字符串是同一字符,那么可以发现一个结论,就是如果下一个还是这种字符那么可以不断向后跳一格,然后直到不能跳,后面的一段都相同那么非法,证明是容易的。

1006

1007

1008

简单题,注意细节。

1009

1010

1011

贪心的选三个中的一个,暴力几次后,就一直是-1操作了。

1012

建立点分树,然后用个线段树做即可。也可以用有序序列+扫指针代替线段树。

1013

可以证明如果 2 i < = n 2^i<=n 2i<=n,那么存在一种操作方式使得可以任意的反转第i位,除了i=1的情况。那么我们用树状数组数逆序对,就知道二进制下第2位是0还是1,其他位暴力一遍即可。

2023“钉耙编程”中国大学生算法设计超级联赛(8)

1001

多项式,不会。

1002

计几,不会。

1003

考虑一个更加松的命题,对于每一条式子,把%n改成%pi,那么就可以化简成 x ≡ q i   m o d   p i x \equiv q_i\ mod\ p_i xqi mod pi,所以就可以使用CRT。然后发现这样子在n以内只会解出一个解,所以只要带回严命题验证即可,若不对,那么就是无解。

1004

线性基+bitset,比较朴素,略。

1005

考虑最优策略是怎么样的。

分三类:

两边都不是我的,那么输。

一边是我的,那么只能取那一边。

两边都是我的,如果有一块的大小>1,那么我赢,否则如果有至少一侧向内一个是一个大小为1的对手的块,那么我取这个之后对手只能取这一个,然后就回归了状态,所以如果至少有一个向内是大小为1,那么就优先取这个,否则说明两边向内的大小都>1,我必输。

1006

考虑对于每一个点求出和T1的最长公共前缀和最长公共后缀,那么我们枚举l和r,使得s[l,r]与T1和T2的合并串匹配,那么就可以知道T2的插入位置可以由上面求出的最长公共前缀和最长公共后缀来限制位置,那么就相当于询问s串的一个区间中T2出现了几次,可以开始时KMP求出。

1007

简单题。

1008

考虑dp,设 f i , j f_{i,j} fi,j表示i个向量,秩为j,那么有 f i , j = f i − 1 , j + p j f_{i,j}=f_{i-1,j}+p^j fi,j=fi1,j+pj表示新的还在这个空间中,以及 f i , j = f i − 1 , j − 1 + p n − p j − 1 f_{i,j}=f_{i-1,j-1}+p^n-p^{j-1} fi,j=fi1,j1+pnpj1表示新的与之前的线性无关,然后就可以转移处理了。

1009

考虑这个是可二分的,我们来找一个快速判断的充要条件。首先我们要满足如图的折线互不相同,这个可以对于每个点记录最近的相同元素出现位置来预处理,对于每个左下角都处理出能延伸的最远右上角。还有一个,就是要满足斜线相同的性质,如图,我们可以对于每一个左下角处理出向右上最远可以延伸的地方是的每个斜线都是相同的,具体的如果 a i − 1 , j = = a i , j + 1 那么 a_{i-1,j}==a_{i,j+1}那么 ai1,j==ai,j+1那么 f i , j = m i n ( f i − 1 , j , f i , j + 1 ) + 1 f_{i,j}=min(f_{i-1,j},f_{i,j+1})+1 fi,j=min(fi1,j,fi,j+1)+1,证明显然,否则 f i , j = 1 f_{i,j}=1 fi,j=1。我们对于每个右上角也处理一个类似的东西,然后就可以左下角掌控一个下三角,右上角掌控一个上三角,分别判断了。

1010

考虑d=abs(a-b)。

如果d是平方数,那么答案是1。

如果d!=2k(k为奇),那么d就可以拆成两个奇偶性相同的数之积,具体是d=(a+b)(a-b),答案为2。

否则,我们暴力判d能否变成两个平方数之和,这是 O ( d ) O(\sqrt d) O(d )的,如果不能,那么可以先d–,那么d就变奇数,可以拆乘积了,答案是3。

2023“钉耙编程”中国大学生算法设计超级联赛(9)

比赛出的不错,但是我打烂了。

1001

1002

考虑dp,这是一个形如变进制数的东西, f i , j f_{i,j} fi,j表示当前这位一位就表示 2 i 3 j 2^i3^j 2i3j,然后 f i , j f_{i,j} fi,j f i + 1 , j f_{i+1,j} fi+1,j f i , j + 1 f_{i,j+1} fi,j+1转移即可。

1003

好像又是考查审题的题目,审完题好像就水了。

1004

1005

简单题。

1006

1007

1008

结论题, a n s = ∑ i < j a i a j ans=\sum_{ians=i<jaiaj,不想看证明了,好像需要停时定理。

1009

1010

1011

考虑容斥,我们用一系列的大小为cnt,权值为-1的物品做背包,那么每一项就对应了容斥系数。考虑怎么加速背包,对于 c n t < n l o g n cnt<\sqrt \frac{n}{logn} cnt<lognn 的,我们可以O(n)处理出对于不同cnt的f数组,然后把它们卷在一起,一共 O ( n n l o g n ) O(n\sqrt {nlogn}) O(nnlogn ),对于其他的暴力做背包,由于 ∑ c n t = n \sum cnt=n cnt=n,所以也是 O ( n n l o g n ) O(n\sqrt {nlogn}) O(nnlogn )。容斥系数求完之后随便算下组合数就好了。

还有O(nlogn)的多项式解法,不想看。

1012

题干抽象,其实就是一个高精或者log化积为和的板题。

2023“钉耙编程”中国大学生算法设计超级联赛(10)

哎,这场真的是打坏掉了,无语,T11想出来了但是脑抽规律找错了,哎。。。

1001

1002

1003

考虑先以a为标号建树,然后再把原排列以n!标回去。

1004

题叕看错了,无语,白推了1h推出错误version的解法,读对了之后发现答案就是(2n-1)/3,在场上是推出来的,这里现在没心情写过程。

1005

1006

1007

1008

题目叕叕叕看错了,看成区间xor了,简单题,压到线性基里面,然后不够的用0补全,然后check一下是否合法即可。

1009

简单题。

1010

1011

我们把它们分成m组,然后用坐标(x1,x2,……)表示一个位置,我们把第一维去掉,变成(x2,……),然后x1=n-1-x2-x3-……。考虑每组怎么标号,我们发现对于(x2,……)(这个是x1=n-x2-……),它去掉每一个位置后会形成(x2,……)和(x2-1,……),(x2,x3-1,……)等。那么我们让前面所提及的第一个标号为1,之后顺次标下去,我们让标号1的赋值为1的组,在位置2赋值为2,在位置3赋值为3等等。那么对于这一组,无论它接受到的信号是什么,都可以选对。然后我们看一下这个相当于是什么,发现就是在坐标系里面行走,如果对于两个相邻位置x和y,如果x=(x2,x3,……),y=(x2,……,xp,……),那么y的组赋值就是x为p的组对应位置赋值为1,其他都没有要求。然后手玩一下发现其他位置有性质就是相对顺序还是1,2,3,……,只是转了一下,这样子可以保证勾勒出所有点,所以我们就在坐标系里面bfs,然后后继的1通过当前的赋值确定,剩余位置依次标下去。具体可以看代码,讲的比较抽象。

1012

简单题。

JSOI2023模拟赛34-泛做

JSOI2023模拟赛34

T1

考虑设计一个和SG函数类似的东西来处理这个游戏,也即对于0状态,每个后继非0,对于非0状态,至少有一个后继为0。考虑怎么设计,我们给无出边的点赋 a i = 0 a_i=0 ai=0,然后 a x = m e x ( a s o n ) a_x=mex(a_{son}) ax=mex(ason),再有 f x = ⊕ [ a i = = x ] v i f_x=\oplus [a_i==x]v_i fx=[ai==x]vi,然后我们发现这样子就有一个好处,就是 a x = p a_x=p ax=p的点,在操作后就可以任意改动 f y f_y fy(y n o w = ∑ f x now=\sum f_x now=fx,这个就是最后的类SG函数了,简单手模就可以发现是满足要求的。剩下部分都是朴素容易的。

T2

考虑这个一看就不是常见的字符串题,所以感觉就不能用SAM等维护,所以考虑hash。我们设hash f ( x , i , B ) f(x,i,B) f(x,i,B)表示 [ x , x + 2 i − 1 ] [x,x+2^i-1] [x,x+2i1]这个区间,base为B,蝴蝶变换后的hash值。考虑有 f ( x , i , B ) = f ( x , i − 1 , B 2 ) + B f ( x + 2 i − 1 , i − 1 , B 2 ) f(x,i,B)=f(x,i-1,B^2)+Bf(x+2^{i-1},i-1,B^2) f(x,i,B)=f(x,i1,B2)+Bf(x+2i1,i1,B2)考虑这里B的幂次和i的值有一定联系,发现这样子的话有nlog^2n个状态,会T,考虑借由联系来减少状态。具体来说只要对于 i = x i=x i=x的所有区间,它们的base是一样的就行了,至于对于i不同的hash的base不要求一样。所以使 i = x i=x i=x的base为 B 2 20 − i B^{2^{20-i}} B220i,发现就可以把最后的两维表示在一起,并且没有丢失信息,可以转移。

T3

考虑枚举数的1的个数p,那么>p的一定放and里面,p的and以及

JSOI2023模拟赛37

T1

考虑DP,用 g i g_i gi表示i子树的方案数,转移朴素,用 f i , j f_{i,j} fi,j表示除去i子树,给i预留位置j,同时也给子树预留位置的方案数。考虑 f i , j f_{i,j} fi,j的转移,要转移到 f s o n , k f_{son,k} fson,k那么j-k一段一定是由一些其他子树凑成,可以背包出来,然后就可以直接转移了,O(n^3),有了f之后答案不言自明。

T2

考虑把两个序列写出来,我们设(stal,star)为当前时间段的基本特征,具体sta就是描述是否运动的,由于 t o t l e n = l c m ( l e n l , l e n r ) totlen=lcm(lenl,lenr) totlen=lcm(lenl,lenr),又这个时间段的段数是 t o t l e n / l e n l + t o t l e n / l e n r totlen/lenl+totlen/lenr totlen/lenl+totlen/lenr,所以段数是O(1e6)的,可以直接对于段来做,然后相当于离散,预处理后可以直接低复杂度查询。具体的预处理和sub50%一样,是朴素的,不再赘述。

T3

JSOI2023模拟赛38

T1

考虑这个要怎么快速做,考虑到定义 a > b a>b a>b表示a可以吃掉b,那么显然对于 a = > b < = c a=>b<=c a=>b<=c的东西里面b删去答案不变,所以考虑设计函数d,有:
d i = 1       i = 1 d i = d i − 1 − 1       s i > s i − 1 d i = d i − 1 + 1       s i < s i − 1 d i = d i − 1       s i = s i − 1 d_i=1\ \ \ \ \ i=1\\ d_i=d_{i-1}-1\ \ \ \ \ s_i>s_{i-1}\\ d_i=d_{i-1}+1\ \ \ \ \ s_idi=1     i=1di=di11     si>si1di=di1+1     si<si1di=di1     si=si1
然后我们发现如果有 d i > = d i − 1 d_i>=d_{i-1} di>=di1 d i > = d i + 1 d_i>=d_{i+1} di>=di+1那么可以把i删掉,显然最后留下的是d的最小值,可以线段树维护。

T2

妙妙题。

考虑怎么搞,我们给s分块,然后在匹配的时候每次一次性匹配一个块的hash来实现跳跃,从而使得效率更高。也就是说,我们设块长是B,那么我们扫到i的时候,用[i-B+1,i]的hash值依次与s的每一个块匹配,然后找到对应的起始点,在这个bool上面赋值。然后在计入贡献的时候,注意最后一块的块长不是B,而是C=(n-1)%B+1,那么我们就看看i-n+1的bool量,在看看[i-C+1,i]与最后一块是否匹配。这样子空间是 O ( B + m / w ) O(B+m/w) O(B+m/w)。考虑最后一项还是太大了,我们来找一个更紧的界。首先一个界肯定是n,其次有效点起的个数最多m-n,所以复杂度就是 O ( B + m i n ( n , m − n ) / w ) O(B+min(n,m-n)/w) O(B+min(n,mn)/w)。B大概取5e4,可以通过。

T3

考虑可以kdt解决, O ( n n ) O(n\sqrt n) O(nn ),常数大,无法通过。

考虑常数小的根号做法。我们有一个这样的东西,在线段树上挂自己对应的区间,然后加入一个点就是在线段树上跳,然后把沿线有的x对应的 t x t_x tx减1,如果有一个 t x ≤ 0 t_x\leq0 tx0那么就可以继续加入。考虑这样子复杂度 O ( ∑ t i ) O(\sum t_i) O(ti)无法通过。优化的话我们就设一个步长B,把 B ≥ t i B\geq t_i Bti的点放在线段树上,这样的话复杂度就是 O ( n n ) O(n\sqrt n) O(nn ),然后在执行B步之后,暴力更新全局的 t i t_i ti,然后重构线段树,一共就是 O ( n n ) O(n\sqrt n) O(nn ),常数只有2-3。

你可能感兴趣的:(c++)