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

IOI2020国家集训队作业

不是很想写nfls的题所以作死开了这个东西,希望能有始有终。

CF504E

就是使用hash,我们考虑两条路径的x-lca部分分别为a和b,设a

CF505E

比大部分题解少一只log。

首先考虑二分答案x。由于正着模拟的时候发现由于有取max的操作所以非常困难,然后我们看看逆过程,可以看作初始值为x,然后每次操作是+=p,然后需要保证过程中始终>=0(这对应着max操作),同时最后的时候权值要>=h。所以我们就一直减a,直到v s [ i ] ≤ ( m − i + 1 ) k s[i]\leq(m-i+1)k s[i](mi+1)k。我们考虑优化过程,我们可以通过v%=a来加快过程,然后考虑每有一次这样子的东西,总的操作数会加1,那么我们就记一个总操作次数,>mk的时候直接return 0,那么复杂度就是O(mk)的了。总复杂度O(mklogv)。具体建议看看代码实现。

CF506E

非常难的题目。

首先可以直接BM过题,但是我不会,略去不讲。

我们考虑dp的话要怎么转移,我们从两端向内一个个加入字符来构成回文串,然后在s的两侧同时匹配,可以发现这样子一个回文串对应的s只会有一个,并不会出现两个导致重复计数的情况。接下来先讨论偶回文串,这样方便处理,我们考虑用 f i , l , r f_{i,l,r} fi,l,r表示考虑了i个字符现在s的[l,r]的字符还没有匹配。

  • 如果 s l = s r = n x t s_l=s_r=nxt sl=sr=nxt l + 1 < r l+1l+1<r f i , l , r → f i + 1 , l + 1 , r − 1 f_{i,l,r}\rightarrow f_{i+1,l+1,r-1} fi,l,rfi+1,l+1,r1
  • 如果 s l = s r = n x t s_l=s_r=nxt sl=sr=nxt l + 1 > = r l+1>=r l+1>=r f i , l , r → a n s f_{i,l,r}\rightarrow ans fi,l,rans
  • 如果 s l ! = s r s_l!=s_r sl!=sr s l = n x t s_l=nxt sl=nxt l < r ll<r f i , l , r → f i , l + 1 , r f_{i,l,r}\rightarrow f_{i,l+1,r} fi,l,rfi,l+1,r
  • 如果 s l ! = s r s_l!=s_r sl!=sr s r = n x t s_r=nxt sr=nxt l = r l=r l=r f i , l , r → f i , l , r − 1 f_{i,l,r}\rightarrow f_{i,l,r-1} fi,l,rfi,l,r1
  • 如果 s l ! = s r s_l!=s_r sl!=sr s l = n x t s_l=nxt sl=nxt l = r l=r l=r f i , l , r → a n s f_{i,l,r}\rightarrow ans fi,l,rans
  • 如果 s l ! = s r s_l!=s_r sl!=sr s r = n x t s_r=nxt sr=nxt l = r l=r l=r f i , l , r → a n s f_{i,l,r}\rightarrow ans fi,l,rans

所以我们简化一下,就是:

  • 如果 s l = s r s_l=s_r sl=sr l + 1 < r l+1l+1<r 25 f i , l , r → f i + 1 , l , r 25f_{i,l,r}\rightarrow f_{i+1,l,r} 25fi,l,rfi+1,l,r f i , l , r → f i + 1 , l + 1 , r − 1 f_{i,l,r}\rightarrow f_{i+1,l+1,r-1} fi,l,rfi+1,l+1,r1
  • 如果 s l = s r s_l=s_r sl=sr l + 1 > = r l+1>=r l+1>=r 25 f i , l , r → f i + 1 , l , r 25f_{i,l,r}\rightarrow f_{i+1,l,r} 25fi,l,rfi+1,l,r f i , l , r → a n s f_{i,l,r}\rightarrow ans fi,l,rans
  • 如果 s l ! = s r s_l!=s_r sl!=sr l < r ll<r 24 f i , l , r → f i + 1 , l , r 24f_{i,l,r}\rightarrow f_{i+1,l,r} 24fi,l,rfi+1,l,r f i , l , r → f i + 1 , l + 1 , r f_{i,l,r}\rightarrow f_{i+1,l+1,r} fi,l,rfi+1,l+1,r f i , l , r → f i + 1 , l , r − 1 f_{i,l,r}\rightarrow f_{i+1,l,r-1} fi,l,rfi+1,l,r1
  • 如果 s l ! = s r s_l!=s_r sl!=sr l = r l=r l=r 24 f i , l , r → f i + 1 , l , r 24f_{i,l,r}\rightarrow f_{i+1,l,r} 24fi,l,rfi+1,l,r 2 f i , l , r → a n s 2f_{i,l,r}\rightarrow ans 2fi,l,rans

所以我们可以建出一个自动机,然后在自动机上面跑矩阵快速幂,可以发现复杂度爆炸。考虑分析这个自动机的形态,可以发现上面有若干点,每个点要么是25的自环,要么是24的自环,同时可以视作每一条s-t的路径方案数独立,每一条路径上的边的权值都是1。那么我们发现有不少的路径形态是类似的,具体的上面点的cnt25和cnt24分别相等,那么两条路径的方案数相同。更加具体,我们发现cnt25=l-2cnt24,所以cnt24一样即可,所以我们就用 f l , r , i f_{l,r,i} fl,r,i表示当前所在自动机节点为[l,r],一共已经有cnt24=i。所以我们就可以对于每一种cnt24计算出有几条路径。然后考虑对于每一种分别记数,一共O(n)种,每种O(n)个节点,所以是O(n^4logk)。考虑继续优化,我们拉出两条链,一条是自环25的,一条是自环24的,然后第一条链上每个节点对应不同情况的s,第二条链上每个节点对应不同情况的t,然后用一个第一条链末尾指向第二条链开头的边来沟通它们,就可以一次矩阵快速幂分别算出对于所有情况的方案数。具体看洛谷题解的图片可能更加清晰。

总结一下就是压方案这个方法比较的妙,一下子就降维打击了,话说这个是第一次见到的在自动机上压方案的题。

CF512D

考虑分析一下性质,可以发现可以变成环肯定不行,两端是环的链也不行,最后就把问题变成了一些树,然后对于一些树有要求就是某个点要最后取,另一些则没有要求。对于第一类,我们考虑树上dp处理一个子树全删的方案数,以及dfn序上的dp来解决“选择若干子树“。对于第二类,我们可以钦定一个,然后考虑会怎么算重,对于一种方案,如果删了p个点,一共有n个,那么对于n-p点做一次计数都会把这些方案计入一次,所以去重除n-p即可。最后把所有树合在一起即可。

CF516D

考虑我们可以直接算出每一个f。看看f的性质,发现可以取f最小的一个点为根,那么随着每个点的f都比父亲d大,这是很好的,发现连通块就是每个点为根的一个子树内的连通块。那么我们可以对于每一个x求出向祖先最多延伸多少,然后对于这一些祖先,x一定是可以加入到它们的连通块里面的,那么dp出向上延伸的长度,然后树上差分打标记即可,一共O(nq)。

CF516E

CF521D

首先肯定是先赋值然后加然后乘,赋值操作只用取最大的那一个,然后可以把这个赋值操作看成加操作。接下来,我们对于每一个元素分别考虑,一定是先每个取一个最大的加操作先用上,然后接下来对于每一个元素我们一定是用最大的加操作或者最大的乘操作。我们发现使用乘操作会使ans变成kans,同理,对于加操作我们也看看会变大多少倍,假设这个元素当前加操作之和为s,那么ans就会变成 s + v s a n s \frac{s+v}{s}ans ss+vans,于是我们也就有了一个相应的k。我们算出所有元素的加操作和乘操作中较大的k,要注意是浮点数,每次操作一定是取所有这些k里面最大的来操作,然后更新对应元素的k,这里我们用一个优先队列模拟即可。一共O(nlogn)。

CF521E

我们发现如果一个环里面有一条边,那么就可以找到题述路径,所以就是跑tarjan,然后看看每个边双是不是简单环即可,这个可以看边双里面的点数边数判断。

CF526F

“contest 934 数据结构选讲”的G题,去那里看题解。

CF526G

笑死了,躺着想题解正确性然后睡着了,醒过来就想出来了。

我们考虑这个的等价命题,就是要求一个2y个叶子的连通子图,然后包含x。我们先考虑把包含x的限制去掉,那么发现一开始一定会选直径,然后直径的两个端点就是两个叶子,我们发现可以等价成一个以直径一端为根,然后长剖,取前2y-1大的长链,这里仔细思考一下就会发现是正确的,这是因为这个和“2y个叶子的连通子图”等价。

考虑引入性质,有三种情况。

第一种是这些里面本来就包含x。

第二种是选2y-2大的长链,然后加入一条x向下尽量延伸,向上刚好触到连通子图的链。向下的长度可以借用长剖的预处理数组,向上的话就用一个倍增数组,维护x向上2^k的链的最小标号,这里标号指当前位于第几大,然后一直倍增找到最浅的标号>2y-2的位置即可,然后向上的长度变成了x的带权深度-求出的点的带权深度。

第三种是选2y-1大的长链,x向上刚好触到连通子图位置设为y,那么把y的长链的下一半换成x向下尽量延伸+x到y的链。就是这个正确性证明把我搞睡着了。这里有两种让人生疑的地方,我画了一张图。一种是为什么一定是选y和x替换,而不是深度浅一点的z和x替换,我们可以发现由于长剖的性质,有z>w+y>y,所以相对来说权值都是多了x,那么减少的权值当然用少一点的比较好,所以会选择x-y而不是x-z。第二种是担心换掉之后会不会产生一个长链z和原有部分不连通了。但是转念一想,发现这个时候”最优“的是加入w+z这一条链,我们就规避了不连通的问题。同时我们发现y>z,所以选择w+y比w+z优,那么方案就变成了x和y+w两条链,可以发现这个涵盖在第二种里面了,所以会出现不合法情况,但是不合法情况肯定劣。

CF527E

先写一下刚开始的想法,然后引出最后解法。

我们发现对于x-y-z-w,我们可以通过x->y,y<-z,z->w连边,就相当于x->w一条边,同理反过来就相当于x<-w一条边,所以我们可以一边找出所有长度为3的链,一边等效替换。这一个过程极难实现,但是也是可以写的。然后我们发现剩下的都是菊花,我们就把一些点向中心连边,中心向剩下的点连边,同时尽量保证入度为奇的点数和出度为奇的点数一样大,再加上对于自环的特殊处理,这一部分就和经典背包差不多,但是用贪心就能解,之后暴力连边,然后替换回去即可。但是整个过程太难实现,特别是最后的贪心部分。所以我们应该思考有没有等效替换后一步到位的方式,也就是把贪心暴力连边部分放在最开始,我们发现如果一开始所有点的度是偶的话,且总边数是偶的,那么等效替换之后一定就是大部分点的度为0,和几个两个点的环,然后就简单了。我们再考虑优化这个过程,我们发现结论和欧拉回路很像,考虑直接欧拉回路,那么发现从一个点进去再出来那么就是形如x->y<-z的,仍然合法,就是如果总边数是奇的话那么起点会是出度奇入度奇,这个时候连一个自环即可。

CF536D

CF538G

CF538H

CF547D

发现建图后类似二分图,所以上下界循环流可过。

正解更加美妙。我们把每个点看做连接横坐标和纵坐标的边,然后我们发现一个形如x->y->z,我们把两个点染为异色,那么y的同色要求就没有被“打破”。抽象的,就是度数为偶的点要求入度等于出度,度数为奇的点要求二者差为1,那么我们发现欧拉回路就可以满足这个要求,而且仔细思考发现是充要的,然后我们把度为奇数的点向一个虚拟点连一条边,发现在这个图上面跑欧拉回路即可。

经过几道题的考验,发现自己真的不会欧拉回路,平时多注意一点。

CF547E

我们考虑建出AC自动机,然后差分询问。我们一个个在AC自动机上面跑并打tag,那么我们就有了一个前缀对应的tag形式,然后单次询问就是询问一个固定前缀的tag的子树和。一共是 O ( ( ∑ ∣ s i ∣ + q ) l o g ∑ ∣ s i ∣ ) O((\sum|s_i|+q)log\sum|s_i|) O((si+q)logsi)

CF549E

首先圈住n个和圈住m个同理,所以只讨论圈住n个。

这个圆肯定是过了n个点围成的凸包的一个顶点。我们枚举这个点,然后考虑圆心要满足什么要求。找了一个充要条件,就是要在这个点和n-1个点的平分线的远离当前点一侧,同时在这个点和m个点的平分线靠近当前点一侧。我们用这些线去看看能不能勾勒一个凸包即可,这部分感觉比较简单,并没有仔细想,应该需要计几知识。考虑到由于是整点,所以凸包的顶点个数是 n 2 / 3 n^{2/3} n2/3,一共就是 O ( n 5 / 3 ) O(n^{5/3}) O(n5/3)。这个顶点个数是不错的trick,一开始还忘了/cf。

CF553E

CF555E

感觉奇怪的图论题都建议向tarjan靠。

首先一个强连通分量里面画一个环就两两可达了。然后我们缩点,对于未处理的询问做一个路径覆盖即可。这个路径覆盖可以这样做,我们打两个tag,一个是向上走的,如果是正说明要求向上,另一个同理,我们树上差分做路径覆盖,然后和回去看看有没有哪个边同时有两个tag即可。O(n)。

CF559E

感觉自己的dp很怪,可能有误。

我们离散化,然后用 f l , r f_{l,r} fl,r表示考虑了被完全包含在里面的线段(向左向右翻都超不出去)的最大覆盖面积。考虑新加入一条边,枚举向右向左翻,以向左翻为例,那么就有[l,p]这一段被覆盖了,所以当前所求剩下一部分就是用了被完全包含在[l,r]的线段,在[p+1,r]这一段里面最多能覆盖多少。我们针对这个多存一个 g l , r , p g_{l,r,p} gl,r,p,然后发现f和g就都可以O(1)转移了(应该说均摊O(1)),一共就是O(n^3)。

CF566C

首先考虑一条链,那么就相当于凸函数之和的最值。那么我们考虑凸函数之和,这还是凸函数,我们从斜率入手考虑,发现两个的斜率都是逐渐递增,所以和的斜率也是逐渐递增。感性理解一下移用到树上,那么也就是一个凸的东西,也就是有一个点是最小的,然后向外逐渐递增,由于是严格递增,所以可以用点分治。考虑点分治过程,我们向一个地方移一点点,所以就是一个斜率相关的东西。我们考虑求导,然后考虑从中心向一个子树移动,那么其他子树的导数都是负的,这个子树是正的,所以就是总导数-2*子树导数,我们取正的那一个走即可。导数的处理想必不陌生,是一个常数乘距离根号。还有一个问题就是中心可能在边的中间,这个的具体表现就是跳完之后,我们再看一圈,如果还有一个跳过去是优的话,那么说明中心在相对应的边上,两个端点都算一下即可。

CF566E

考虑对于a-b-c-d,我们如果把a和d的集合交在一起,会发现只有b和c两个元素,同时发现如果是a-b-d,那么交起来有abd三个元素,如果a-d那么外面一定有(除n=2),所以至少三个元素。所以我们两两交,然后就可以把所有非叶子节点构成树勾勒出来。

先把菊花图特判掉,枚举中心来特判。

考虑怎么挂叶子,我们已经知道叶子有哪些编号。我们遍历一遍,然后把所有含这个叶子的集合交在一起,发现所得就是叶子的集合,然后就可以唯一确定叶子位置了(除n=4且形如a-b-c-d)。

我们再把n=1,两个括号里面的形式,菊花图三种特判掉即可。

CF568C

我们首先2-SAT,(p1,t1)向(p2,t2)连边。然后从前往后dfs,考虑当前可不可以确定恰好是这个,再跑一遍2-SAT来check,可以的话就递归下去否则就换一个来check,可以证明如果当前check可以,那么下面一定存在一种选择方式使得满足2-SAT,所以说不会回溯,除非是字典序那里出现了矛盾(就是2-SAT要求必须某一种,但是那一种最大的也太小了),这种矛盾只会出现一次(因为回溯回去之后当前字典序就是严格大了),所以还是check次数O(n)的,一共O(nm)。

CF571D

写过但是发现我的博客被吃掉了(好像是误删),所以只好再写一遍/kk。

对于第一类和第二类用合并操作树重新赋dfn,操作等价于一维坐标上的区间操作,然后可以刻画一个矩阵,然后就可以KDT了。

然后我们尝试把第一类和第二类分开来优化复杂度。我们发现当前值就是最后一次被清0的时刻到当前时刻对一操作的和,也即两个s之差,我们可以通过可持久化线段树查询任意时刻的s。我们获得这个时刻就是对于二操作建一个线段树,然后操作就是一个区间覆盖时间tag。我们可以通过二操作之后再扫一操作,那么就可以把可持久化去掉,时间O(nlogn),空间O(n)。

CF571E

我们考虑创造一个merge操作。考虑当只有两个序列的时候怎么合并,对于每一个质因子,我们可以列出一个等式组形如 a 1 + b 1 x = a 2 + b 2 y a1+b1x=a2+b2y a1+b1x=a2+b2y,对于每一个式子的x和y都是一样的。考虑怎么解,我们可以尝试相邻两个式子构成一个组,具体就是把x消掉,如果可以解出y那么就解然后验证,否则说明两个式子线性相关也就是等价,最后分三种情况,一种是无解,那么就判不存在,一种是解出了具体值,代到每一个序列里面检验一下即可,一种是所有式子线性相关,那么我们就用裴蜀定理+exgcd,把x写成形如kx+b的东西,然后就实现了合并。这里我们不是简单的储存a和b,而是拆开存在vector里面,可以证明如果有解,那么每个序列的含有的质因子相同,所以质因子总数是O(loga)的。所以复杂度就是O(nloga)。这里还有一个问题,就是这个x会不会爆long long,考虑到最开始每个值都是<=logV<30的,由于exgcd求出kx+b过程的上界的量级和取lcm差不多,所以我们可以感性理解最后x的量级和30以内的数的lcm差不过,这个是2329089562800,距离爆long long还有几百倍,所以不会爆。实在不行__int128绝对没问题

CF573E

和“contest 912 贪心 E”撞了,去那里看。

CF575A

过来搞笑的。

我们画出矩阵,然后做一个前缀积和后缀积,然后就可以通过后缀积+循环节快速幂+前缀积快速跑过若干矩阵了,然后我们就快速从一个断点跳到下一个即可。一共O(8mlogn)。

CF575E

CF575I

对于每一种旋转后都一样,所以我们拆成四个维护,这里只用给出一种形状的维护方式。如图1,我们发现可以在矩阵上面打这样子的tag,这样子一个矩阵前缀和就是单点值了。考虑怎么快速的做斜线加,这个用线段树应该是容易的,外层坐标是x,内层坐标是y,外层采用标记永久化,内层采用lazytag或标记永久化,然后是一个矩阵加的变体了,并不难维护。但是不如追求更加有挑战的二维BIT。如图1,对于线1,那么我们可以用x3-x1计入,对于线2,我们可以用y3-y1计入,我们发现采用x还是y是由这个斜线的x-y的值决定,所以我们用二维BIT,一维表示x-y,一维表示x,然后查询矩阵和,但是不幸的发现会出现如图3的情况导致多算。但是发现如果如图4割到长边那么就不会有多,所以我们分两类一类是可以直接查询,另一类是一个矩阵查询减去一个直接查询,那么就惊奇发现没有问题了。然后一个矩阵记常数,一个矩阵记x3和y3前面系数就好了。发现最后常数和线段树旗鼓相当,由于线段树还要打tag,有32左右常数,所以可能还是少一点。话说我记得三角查询不用这么麻烦的呀/fad。

再写一下题解做法,好像常数比我小8倍的样子。我们直接支持三角加,然后支持方式如图5即可。这样子的话我们只用x-y和x的BIT,x-y和y的BIT,x+y和x的BIT,x+y和y的BIT,四个即可,还有x-y,x+y的一维BIT,感觉比我的好多了。之后我们用差分把矩阵加+单点查询改单点加+矩阵查询。这个trick我要了。

CF576D

题目审错了。

我们考虑处理出有了前i条边的时候的局面,这个可以用矩阵快速幂+bitset做。然后我们就知道当前可以到达那些点并去掉了d的限制,这是我们再一个多源bfs即可。

CF576E

又是一道题解被误删的原题/kk。

我们考虑使用线段树分治+可持久化扩展域并查集。注意每次要判断当前操作是否执行,具体来说先一次性放到线段树,然后扫到某一个节点的某一个操作,要追溯到时间最近的相关可执行操作来操作。

CF578E

原来做法假掉了/kk。我们考虑把它贪心的尽量少的剖分成"LRLRLR"和"RLRLRL",同时可能会多一个"RLRLR"或"LRLRL"(如果有多个可以调整成一个,在构造部分有讲),考虑这个剖分个数显然就是答案(感性理解这个就是上界,那么只要可达也即构造方案,那么就是解),我们看看怎么拼在一起。首先"LRLR"可以首尾相接,拼成形如"LR"的东西(用两侧的特征表示),同理也有一个形如"RL"的,如果有一个形如"RR"或"LL",那么就可以接在一起了,如果没有,那么考虑如果 p o s L ( L R ) < p o s R ( R L ) pos_L(LR)posL(LR)<posR(RL),那么接成 L ( R L ) R L(RL)R L(RL)R即可,这里面最左边的L只是一个脚印,另外一种情况同理。考虑怎么剖分,扫一遍如果下一个是R,那么优先接到"LL"的上面,否则接到"RL"的上面,其他同理,不行就新建,这也就说明了"LL"和"RR"不同时出现(“LL"用完了才去造"RR”),而又 a b s ( c n t L − c n t R ) ≤ 1 abs(cntL-cntR)\leq1 abs(cntLcntR)1,"LL"和"RR"又是会引入差异的,所以最多一个。

CF578F

与“contest 872 树上 H”重复,去那里看。

CF582D

就是kummer定理+数位dp,思想并不难,难在数位dp的实现,这里不赘述。

CF582E

CF585E

考虑倍数莫比乌斯反演:
F ( n ) = ∑ n ∣ d f ( d ) f ( n ) = ∑ n ∣ d μ ( d / n ) F ( d ) F(n)=\sum_{n|d}f(d)\\ f(n)=\sum_{n|d}\mu(d/n)F(d) F(n)=ndf(d)f(n)=ndμ(d/n)F(d)
其中我们依次考虑每一种 a x a_x ax,然后f(d)就表示满足 g c d ( a x , g c d i ∈ S a i ) = d gcd(a_x,gcd_{i\in S}a_i)=d gcd(ax,gcdiSai)=d,且 g c d i ∈ S a i = 1 gcd_{i\in S}a_i=1 gcdiSai=1的S个数,然后我们要求的就是f(1)。代到式子里面会发现只有 d ∣ a x d|a_x dax的时候 F ( d ) F(d) F(d)才会有值,所以我们枚举每一个 a x a_x ax的因子去求F(d)。怎么求F(d)呢,就是我们取所有为kd的值的 a i a_i ai,设有cnt个,那么就有 2 c n t − 1 2^{cnt}-1 2cnt1种方式(不能选空集).同时注意由于有 g c d i ∈ S a i = 1 gcd_{i\in S}a_i=1 gcdiSai=1的限制,所以F(1)不能这样子简单计算。我们考虑如何计算,就是除了 a x a_x ax以外的数有多少个集合的gcd>1,那么我们可以再运用倍数莫比乌斯反演,我们设f(d)表示gcd为d的集合个数,那么我们就求f(1),然后之后都是类似的。我们发现这样子要调用n个F(d),但是我们发现对于去掉了不同的 a x a_x ax,只有 a x a_x ax的约数的位置对应的F(d)是不一样的,对于这些特殊处理即可。一共就是调和级数O(VlnV),由于n和V不同级,可能还比这个小一点。

发现大多数人是loglog的dirichlet前缀和,并不会。其实就是上述过程统一处理来加速,具体的也是先算出全局然后用dirichlet来加速算每个点的少了的贡献,懒得展开讲,可以看lg题解。

CF585F

CF587D

首先二分,然后考虑2-SATcheck,对于大于阈值的我们1->0强制不选。我们考虑对于每一个点都是一个限制,就是对于每一个边都不能和与其他有这个点的边同时选。我们考虑对于每一个点用前后缀和优化,这样子就可以每个点的1向其他点的0连边,同时不会向自己的0连边。

CF587F

CF590E

CF594E

CF603E

原题,但是原来做法假了/kk。

我们考虑充要条件就是每一个连通块的大小都是偶数,而且这个是有可二分性的,就是加了一条边,只会变优。考虑一个算法,我们线段树分治,然后从左向右扫,找到了一个叶子的时候我们把所有没有用过的边从小到大依次扔进去,那么就可以知道我们需要哪些边,而且由于答案在从右向左过程中递增,所以这些边在可以用的时刻到当前都是可用的。而且权值比这些小的边,如果没有用,但是由于有可二分性,所以加入是无妨的。所以我们把这些边和权值比这些边小的边所对应的可用节点都压到线段树上面,这样子在之后分治的时候就可以加入了。然后从叶子回撤的时候,上面那些“实验”用的边要全部撤回。考虑这样子的时间复杂度,在一条边被“实验”之后,就不会再被“实验”了,因为应该有的位置都用线段树cover掉了。那么如果一条边被考虑了一次,也就是在叶子用并查集尝试了一次,那么就永远不被尝试了,所以叶子节点处的时间复杂度,由于每一个只会被“实验“一次,所以是O(nlogn)的。在其他位置,由于是线段树分治,而且只cover了O(n)次,所以是 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)的。

CF605E

我们考虑怎么做。我们考虑当前点,假设我们已经知道它的每个出边对应的点到终点的期望最小距离。那么显然每次如果随到了比较短的当然要走短的。首先看看哪些边走了一定不优。对于两种 ( d x , p x ) (d_x,p_x) (dx,px) ( d y , p y ) (d_y,p_y) (dy,py),假设我们随到了y,但是 d y ≥ d x + 1 / p x d_y\geq d_x+1/p_x dydx+1/px,也就是如果不走而是要走x,那么期望情况下还是比y优,那么肯定不走y。我们把肯定不走的去掉,那么剩下的都可能通行。考虑按照d从小到大排序 ( d 1 , p 1 ) , ( d 2 , p 2 ) ⋯ (d_1,p_1),(d_2,p_2)\cdots (d1,p1),(d2,p2),那么随到了1就不会走2,后面类似,所以对于当前,我期望到达终点就是 1 + d 1 p 1 + d 2 p 2 ( 1 − p 1 ) + d 3 p 3 ( 1 − p 1 ) ( 1 − p 2 ) + ⋯ 1+d_1p_1+d_2p_2(1-p_1)+d_3p_3(1-p_1)(1-p_2)+\cdots 1+d1p1+d2p2(1p1)+d3p3(1p1)(1p2)+,同时有 ∏ ( 1 − p i ) \prod(1-p_i) (1pi)的概率走不出去,对于走不出去的情况,那么就会到下一层,下一层的决策和当前本质相同,所以其实我们就是多一个“走出去”要求带来的等比数列,设 ∏ ( 1 − p i ) = P \prod(1-p_i)=P (1pi)=P,那么最终结果就是 ∑ i ( 1 − P ) i − 1 + 1 1 − P ( d 1 p 1 + d 2 p 2 ( 1 − p 1 ) + ⋯   ) \sum i(1-P)^{i-1}+\frac{1}{1-P}(d_1p_1+d_2p_2(1-p_1)+\cdots) i(1P)i1+1P1(d1p1+d2p2(1p1)+),前面那一个是可以写成封闭形式的,现在懒得算。

然后我们发现当前是“已经知道它的每个出边对应的点到终点的期望最小距离”,所以考虑怎么处理这一个限制。我们发现我们处理过程中一定是d递增的,所以我们每次选上述式子最小的一个转移就是正确的。每加入一个我们可以对于每一个未算位置更新,那么先判一下这个和 m i n ( d + 1 / p ) min(d+1/p) min(d+1/p)有无冲突,然后由于这个一定是最大的,所以在上面那个d和p的和式里面加入一项即可,所以是O(1)更新的。一共就是O(n^2)。

CF607E

CF611G

CF611H

CF613E

和“contest 861 DP专题 D”重了,去那里看题解。

CF626G

和“contest 912 贪心 A”重了,去那里看题解。

CF627F

nfls 4.25-5.4 集训记录

4.25 NOI2023-div2训练赛8

100+100+100+70 感觉还行

T1

带博弈的DP,难度一般般,看清题干!两个人的目的都是最大化!

T2

好题。

考场做法:离线,将边从小到大加,每个连通块维护所含的询问以及每个询问已经藏几次勾,关注连通块合并,首先,可以把无法参与合并的询问剔除,更新ans,剔除的话用set每次取头判一下即可。考虑更新询问藏勾数,对于两个连通块,相当于两个全局加,那么维护全局tag即可。然后合并set用启发式即可。注意计算询问数以及启发式时不要忽略tag的贡献。

正解:注意每次肯定是当前连通块连出的最小边,那么先建出最小生成树,那么最终必然是最小生成树上的一个连通块,相应的就是kruskal重构树上的一个子树。可以建出kruskal,然后预先计算从x开始跳,跳到2^i祖先的最小始值,询问时在kruskal上倍增即可。

T3

神秘题。

正解是一堆状态的轮廓线DP,实现有很多方式。考场做法是直接爆搜+剪枝,可以把复杂度剪对,且比正解快,具体怎么剪没啥学习价值,可以看代码。

T4

此时我网络流才学1天,被薄纱了。

正解就是朴素网络流,我的70是网络流40+模拟退火30。

4.26 NOI2023-div2训练赛9

100+100+70+100 没AK很搞笑

T1

挺有意思的构造,考虑先处理AC和BC,为了有尽量多的AB可能,所以B尽量删靠前的,A尽量删靠后的,同时计算AB,BC,AC应有的上限,删到上限就停。同时考虑AC与BC皆可行时,A有可能可以删更后的,但B已是最前了,所以删BC更优。删完AC和BC后,删AB就很简单了。

T2

伞兵题,提前计算,然后排序啥的就好了,比T1水qwq。

T3

证明我的基础真的很拉。

考场做法:枚举超过一半的集团,然后考虑DP是O(n4)的。考虑限制DP边界[-c[i],c[i]]就变成O(n3)。考虑套NTT转移就变成O(n^2logn)。NTT常数大过不去QAQ。

正解:考虑再优化O(n3)的DP,再在限制上加上[-sz[i],sz[i]]的经典限制,就变成O(n2)了。(神秘,考场上想了不敢写,告诉我要学习计算复杂度和胆大心细)接下来考虑证明复杂度,自己口胡了一个细节都没处理qwq。考虑合并两个数组时,若两个的sz都大于c时,最多有n/c个没有元素重复的f,那么两两合并最多合n/c次,共O(nc);若一个的sz大于c,相当于c个元素与所有元素两两进行一个贡献,总共O(nc);若sz都小于c,显然不妨设每个集的大小相同为B,那么类似情况一,共n/B组,合并复杂度B^2,共O(nB),又B上界为c,故为O(nc)。所以总的是O((sigma c)*n)=O(n^2)。

T4

能重zxj的题也是挺厉害的。

就是一个线段树trick,维护考虑行集为sta时的所有c,这样区间赋值操作就可以更新实现了。一遍过祭。

4.27 NOI2023训练赛9

100+100+70+20 属于是超常发挥

T1

第一眼感觉很神仙,想到了消防局设立感觉这题非常不可做。

然后想想想,还是回归 f [ i ] [ j ] f[i][j] f[i][j]表示第i个点,级别为j的最大价值,然后 f [ i ] [ j ] = v [ j ] − w [ i ] + ∑ m a x { f [ s ] [ j − 1 ] , f [ s ] [ j ] , f [ s ] [ j + 1 ] } f[i][j]=v[j]-w[i]+\sum max\{f[s][j-1],f[s][j],f[s][j+1]\} f[i][j]=v[j]w[i]+max{f[s][j1],f[s][j],f[s][j+1]},其中j=0时特殊一点处理即可。

T2

为什么会有这种神秘题QAQ?

考场做法:考虑把图画出来,花了30min,发现是一个圈,中间有很多平行横线,然后发现其中四元组很有趣。考虑四元组对角线元素之积为1,所以取n/4个随机数以及它们逆元赋0,剩下赋1即可,得到了66pts的好成绩。时间不多的时候,考虑到在环上每次跳跃步长相同时,取得的数十分均匀,于是每次乘上一个数而不是纯随机,然后0pts,发现没有WA而是TLE。开始思考思考,想到应该取原根为步长,于是贺了一个板子,然后就过了。至于为什么对就不懂了?也从“均匀”方面感性理解吧,确实这样比较劣,还卡了一下从取 0.25 ∗ n 0.25*n 0.25n改成取 0.23 ∗ n 0.23*n 0.23n个数才过。

正解:考虑四元组实质是形如 i → i a → a 2 i → a i → i i \rightarrow \frac{i}{a} \rightarrow \frac{a^2}{i} \rightarrow \frac{a}{i} \rightarrow i iaiia2iai,发现当a为二次非剩余时,取出所有二次剩余当做i,那么 a 2 i \frac{a^2}{i} ia2也都是二次剩余,构成一对,同时 i a \frac{i}{a} ai a i \frac{a}{i} ia都是二次非剩余构成一对,又大概有n/2个二次剩余,所以取所有二次剩余为0,就可以保证四元组中两个0两个1。这样比较优,甚至大概小于13n的。

T3

真的魔法QAQ。

考场做法:怎么限不同?怎么限不同??怎么限不同???我会容斥!考虑了容斥重复数量,容斥第一个重复的,容斥……全假的QAQ。从根本出发考虑 f [ i ] [ j ] f[i][j] f[i][j]表示前i个数互不重异或和为j的方案数,考虑转移。显然可以令第i个数随便动,然后前i-1个用互不重,考虑此时前i-1个中与i重的有0个或1个。然后考虑强制前i-1个中有一个与第i个相同,那么重1个或2个,强制2个就是重2个或3个,以此类推。考虑边界就是重i-1个,可以与重i-2个或i-1个的容斥一下,然后得到重i-2个的,然后再向前如此容斥即可。把容斥系数摸出来,组合数搞一搞。然后发现i个互不重与1个任意的异或和为j的方案也不能直接做,可以将一个常值(全是1)与 f [ i ] f[i] f[i]进行FWT得到这个g,于是又贺了一个板子。然后就变成 O ( m 2 n l o g n ) O(m^2nlogn) O(m2nlogn)的搞笑做法,得到了20pts的好成绩。考虑n为2k-1情况,然后把$f[i][j]$自然改成i个不重数异或和有j个1的方案数,g同理,把组合系数改一下,把FWT改成O(logn)的就好了。复杂度$O(m^2logn)$,只多了15pts。考虑优化掉一个m,把组合系数改改,发现可以做一个sum来O(1)转移,而不是一直for来转移,于是少了一只m。下面n=2k-1,m=5000的过了,上面n=1000,m=1000同理改下也过了,于是得到了70pts的好成绩。但是貌似我的做法与正解不沾边,所以没法优化成正解QAQ。

正解:不会。

T4

mad我费用流还没学!!

考场:发现是一个与阿丑探讨过的一个不可解网络流模型直接自闭,于是打了状压DP10pts和k=1的10pts就摆了。

我要学费用流!!!

4.28 NOI2023训练赛10

100+30+20+10 真实实力暴露了QAQ

T1

一开始想的是线段树分治,想了1h写了个 O ( n l o g 3 n ) O(nlog^3n) O(nlog3n)的跑了30pts,不愧是我。然后发现类似矩阵面积那题改下线段树tag就可以省掉线段树分治。写完的时候隔壁电脑都修好了QAQ。

T2

根本不会,连矩快复杂度都写不对QAQ。

想起来当时矩快有个问题,就是要注意不要在main,或其他函数里开大数组,如果考试真出玄学错误,不要慌。首先断点发现错误,如果断哪都不对就眼睛看。然后如果15-20min都没找出问题根源就先跳题,迟点再找或重构。

T3

根本不会,连数位DP都没时间打QAQ。

T4

根本不会,连点分治和另一个部分分trick都没时间打QAQ。

4.29 NOI2023训练赛11

100+100+32+35

T1

暴露了我根本不会处理细节的事实QAQ。

暴露了我没有学过slope trick的事实QAQ。

感觉我好废物啊。

考场做法:所以这题就是考虑每个连续块向上移动的距离为 a i a_i ai,于是有 a i + s i − t i − 1 ≤ a i − 1 ≤ a i + t i − s i − 1 a_i+s_i-t_{i-1} \leq a_{i-1} \leq a_i+t_i-s_{i-1} ai+siti1ai1ai+tisi1,然后就可以写出一个DP转移式。发现是从上一个的一个区间min转移过来,然后加上一个规整的V,于是就想到了维护一个凸包,然后平移一下,在把拐点(最小值)拉长,再与V加一下,一顿操作后发现还是一个凸包。不会维护凸包QAQ。想到这里只用了30min,但发现根本打不出来。直接自信打平衡树,维护每段的斜率和长度,然后打了1.5h,发现细节好多就自闭了。于是继续思考,展现了think twice的价值。我们可以开一个平衡树维护每个V的端点位置,那么整体平移等价于整体加;那么最小点拉长就是把平衡树裂成两个等大的树然后拉开一段距离,注意要更新多算的答案,发现多算的就是拉开距离乘总结点数一半;加一个V就是简单insert;最后暴力找到最优决策点直接算就好了。打了1h,然后发现V字总数是奇数时根本拉不开,又自闭了。于是继续思考,展现了thick thrice的价值。我们可以一次加上两个V而不是一个,这样就一直是偶个了,于是又打了0.5h。发现已经3.5h了QAQ。所以知识点要学全,细节处理要明晰,码力要强,就可以像杜老师一样30min过题了QAQ。

正解:就是普通的slope trick。不如我的方法好写

T2

考场做法:直接10min过题。考虑对于每位就是让sa和sb同时异或上a[i]^b[i],那么就把这些丢到线性基里,然后从高位到低位贪心(类似求异或和最大),如果两个都是0就可以异或上这位线性基,但是如果一个0一个1要考虑这个线性基还可以继续用,去掉最高位然后再丢一次。正确性应该是对的,但是听说数据巨水。

正解:也是从高到低贪心,考虑固定了某位就相当于固定了这位一0一1的ab对交换对数的奇偶性,然后就变成一个异或方程组,用高斯消元判一下就好了。看了一下别人代码,好像有一亿种解法

T3

不会,好像爆搜就好了,我是伞兵。

T4

不会。

4.30 NOI2023训练赛12

100+26+0+0 rnmtq

T1

所以就是考虑位两两之间的贡献,然后把k改为儿子向k级祖先贡献。然后被卡空间,于是写了个先向重儿子(dep大的)走,同时父亲继承重儿子,同时有废物利用,然后分析一下空间就对了。

T2

mad把我干麻了。先是自信想100pts想了2h,发现不会。然后自信写66pts,写了1h,发现假了。于是直接弃赛。

正解:我们发现有一个 f [ i ] = m i n { m a x { f [ j ] , p ( j + 1 , i − 1 ) } } f[i]=min\{max\{f[j],p(j+1,i-1)\}\} f[i]=min{max{f[j],p(j+1,i1)}},发现p(x,y)在y固定时是随x递增而非增,于是思考画出在y固定时p的图像,同时思考f如果有个左侧的点比右侧的某个大,那一定不优,于是用fmin(j到i的min)来转移即可,发现是不降的,再画出fmin的图像,然后取出上半支,然后取最小点。可以思考二分出的交点,然后转移点就只可能是交点两侧的两个整点。所以fmin用个st,然后就nlogn了。如果st改成树状数组然后树状数组上二分,可以直接卡过。

考虑优化。显然有决策单调性(对于同个位置p函数会不断上升然后f会不断下降),所以可以改用若干单调队列,然后直接向右暴力找。

T3

弃赛了,写个锤子。

T4

弃赛了,写个锤子。

4.30 NOI2023训练赛1(补)

T1

比较厉害,最难的题放T1也是挺有新意的。

首先肯定动态DP,所以修改有个 l o g n logn logn,询问有个 l o g 2 n log^2n log2n,这两个是跑不掉的。显然有个暴力矩阵乘法做法,摸个40pts没问题。

考虑优化矩乘过程。

考场做法(假):考虑一个DP式子 f [ i ] = m i n j ∈ [ i − a i , i − 1 ] { f [ j ] } + 1 f[i]=min_{j \in [i-a_i,i-1]}\{f[j]\}+1 f[i]=minj[iai,i1]{f[j]}+1,推导过程就是改为倒着走。然后我们考虑一个类似自动机的东西,丢入前几个数就可以直接推到后面,因为这里f[i]的DP是一个前缀转移过来,所以对于任意两个f[i]和f[j],由它们能向前到达的位置就可以看出它们的偏序关系,然后就可以直接推了。所以当我写到这里的时候就发现自己假了。因为真的不能看出偏序关系,可能后者会走到两者之间的位置,然后有大量油向前飞跃。

正解:考虑改下DP定义,改为以i的油量进入,然后保证费用最小出来时的最大油量。那么就可以十分容易的转移了。但是还有一个关键点,就是考虑下一段可能开头一段劣的一坨大便,所以这里可以预先多花费1的费来get最大油量。那么转移就是O(a),然后询问时广义向量乘矩阵就是O(1),向量大小大概是2,一个是初始给的,一个是多花费1费达到的。

T2

有个有趣科技。qwq

正解:考虑用莫队来实现区间询问的加边,然后考虑tarjan时图十分稠密会变成n^2就炸了。所以有一个不被人所知的Kosaraju 算法。我们可以加快此算法的流程,因为考虑只用访问未去过的点,所以用一个bitset来维护还未访问的点,然后用位运算直接找到下一个点,所以就变成了n^2/w。

赛后思考:这里用猫树分治同样有理有据,询问可以从 O ( q m ) O(q\sqrt{m}) O(qm )砍到 O ( m l o g m ) O(mlogm) O(mlogm),空间增到nm/w,然后在运行算法时,先把两个bitset或一下得到新的,然后再做就好。但是考虑到本题数据特性,应该会变慢。

T3

最近几场比赛已经撞了zxj三道了,但是也可以看出我越来越菜。QAQ

考场解法:想了好几个但是猪脑过载都假了。最终应该是考虑两块,一个是构成最长路的一块,一个是剩下的。考虑剩下的必须都是向最长路连边,否则最长路变长,证明略。剩下的之间可以任意连边,所以这块的计数水了。剩下的话考虑容斥,先是随便连,然后减去长度不满足的(这里相当于询问i个点最长路j,是我们之前已经计算好的)。

T4

想了1h发现假了,大哭。

正解是根号的,发现我的根号算法巨拉,一个这题一个ZJOI众数,都没做出来。首先先考虑一个暴力的,把所有的区间都取出来,然后就变成了一个二维偏序问题,考虑区间数多但询问少,于是运用根号平衡思想就变成了 O ( n 2 + m n ) O(n^2+m\sqrt{n}) O(n2+mn )。在看另一个暴力,我们枚举是哪一对颜色。然后把询问区间扫一遍,简单差分一下(我的假做法中有)就好了。然后两种根号分治一下就过了。

4.30 NOI2023训练赛2(补)

T1

发现自己是盲人,题干叕看错了。

挺有意思的网络流,感觉没见过这个类型。就是典中典二分图染色,然后定义黑格横进竖出,白格竖进横出,然后考虑用流量平衡来限制条件。我们拆点为s->x1->x2->t,然后x1->x2满流就是不选这条边。然后x到y有边就连有向边,费用处理是简单的。那么我们可以发现一个环就是在这个图上出现了一个置换,这就满足了条件,十分有趣。要怎么处理特殊格呢?就是预先断掉x1->x2强制即可。然后最大费用最大流,要求流量为n*m,否则无解。

T2

挺nb的一道题,首先不会,其次会了也码不出来。

考虑这个限制是什么,发现最远端就是 ( m i n j = i n n x t j ) − 1 (min_{j=i}^nnxt_j)-1 (minj=innxtj)1。然后就是一个很典但是我不会的线段树,就是合并时在左二子上二分,得到哪一段要更为右儿子中的minnxt。这样之后答案处理也就是朴素的。然后这个线段树的可持久化是朴素的。考虑怎么找nxt,这就是一个很抽象,但又感觉很常见的trick。维护一个权值线段树代替set,那么就实现了set的可持久化,找后继大概是线段树上二分(胡的)。但是每次把所有权值线段树复制一下就炸了,那么我们再开一个线段树,维护每个颜色对应的权值线段树的根,然后这个也可持久化,那么每次继承一次改一次即可。所以是个三种线段树码农题,不会写。

T3

就是猜结论,发现就是中间没有经过其它点的点对数,然后枚举deltax,deltay,两个sigma,推推式子就好了,发现这里改枚举delta还挺妙。

T4

计几去死。

5.1 NOI2023训练赛13

100+100+20+14 自我感觉良好,大概有一段时间进心流

T1

考场做法:给我做麻了,所以一开始用的是一个SA加哈希比较字符串的 O ( n l o g n ) O(nlogn) O(nlogn)trick,发现要写两个SA,加上SA的合并,加上一堆细节,直接自闭。

于是决定先写 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)的只有哈希比较字符串的快排,然后完全不会处理细节,直接1.5h没掉。然后T飞了,50pts。于是改了下变成自然溢出,就还是TLE50pts,QAQ。然后快乐发现6种比较中的三种比较里,有效的点只有3n个点,另1种还不会。于是就预处理了3n个点时的答案,常数小掉,90pts。然后考虑到在判了两个后,画一画就发现可以转成另一对的lcp,然后就也包括在预处理里了。所以直接 O ( n l o g n ) O(nlogn) O(nlogn)跑过了。

正解:发现SA常数大好像只有90pts。然后正解就是把预处理改成exkmp,十分合理。所以震惊发现有人考场写SAIS,然后也过不了,笑死了SA的cmp过程被卡死了。

发现有人SA过了,值得学习,首先是SA的等号换成异或,其次是初始桶大小设为合理的26,还有使用stable_sort,最后cmp是像我一样预处理了五种,第六种大概是没推出来,总的来说就是卡过了。

然后学了一下stable_sort,发现sort原理是结合快排堆排插排保证了不会退化,stable_sort是归并排序。可以都试试来卡常。

T2

又麻了,推了1.5h的式子,我还是不行啊。QAQ

所以发现就是 2 n − 1 2^{n-1} 2n1除掉几个2,然后2的个数就是判断杨辉里的几行中的段是2的几次幂,然后由kummer定理发现这个值很小,暴力做就80pts了。然后类似T1预处理就少个log就过了。(感觉我写题解写了个寂寞)

听了题解发现好多东西。首先是 n ! n! n!中2的次幂可以O(1)快速算,具体就是公式 2 ∗ x − _ _ b u i l t i n _ p o p c o u n t ( x ) 2*x-\_\_builtin\_popcount(x) 2x__builtin_popcount(x)推导过程可以由模拟while除2的方法得到。其次是用这个利器一方面不用预处理就2只log,另一方面可以考虑要处理的三角部分只有最边界的一条是有效的(可以用2-adic的性质退出,因为边界和旁边一个会推出上面一个,而 a c i d ( 2 x + 2 y ) = m i n ( x , y ) acid(2^x+2^y)=min(x,y) acid(2x+2y)=min(x,y),所以上面合理,旁边合理,那当前必合理),于是就变单log了。

话说想起来考试时三只log的时候,我手动Ofast,然后long long全改int,然后原来还80pts,一下整到50pts了。这时不要怀疑,再交几发,事实证明真的是评测机波动。在考试时推翻原有常识是可怕的事,所以要坚定已有知识。

T3

又麻了,我求导和网络流学了个寂寞。

T4

不会。

5.1 NOI2023训练赛3(补)

T1

话说最近假的频率有点高,危,所以要think twice!

所以发现就是二维平面上的一个神秘博弈。我是先手,如果发现最大s和最大b是同一个,那直接赢了,但若不是这样就必输,所以肯定不会去选最大的s或b。故而把周围一圈直接去了,然后重复此过程即可。

T2

考场做法:自己想的,先写下来再看题解。我们考虑一条条边走,维护每个点所有情况的 ∑ 1 \sum 1 1 ∑ s z \sum sz sz ∑ s z 2 \sum sz^2 sz2期望。首先一个考虑合并两个点,因为每次搞完一条边后就删掉了,所以两个点的信息是相独立的。那么 ∑ 1 \sum 1 1就是相乘, ∑ s z \sum sz sz是左sz乘右1加右sz乘左1, ∑ s z 2 \sum sz^2 sz2也可以简单计算,懒得写latex了。那么考虑断一条边时怎么算,就是左并到右上,和右并到左上,然后啥啥的,也好搞。考虑算答案,是 s z ∗ ( n − s z ) sz*(n-sz) sz(nsz),拆成两部分,然后随便算算就好了。

正解:我大概是对的,题解就是改期望,这个我也想过了,但是感觉不改更直观

T3

不会,非常奇葩的题。我们把初始的点(不包括并联引入的点)看作二叉树的叶子,复合操作看为两个子节点连向父节点。然后用一个 f i , j f_{i,j} fi,j表示考虑到结点i,源汇是否与外界连通状态为j的最大停车数,然后就可以DP,过程中再开一个数组记录一下转移点就行。

这道题告诉我在图模型极为复杂,而又极为特殊,反例特例极多的时候,不要以为自己可以用贪心和构造的一点勾八能力想清楚,而是想下怎么依靠性质将模型转换为常见的。还有告诉我在一个建模为几个什么东西以特定方式合并(如点,数组,集合)成最终,然后要计算最终的一些值,可以考虑树建模,然后投射到树上操作。

T4

神秘题,所以用dfs返祖边根本做不了(可能是几条返祖边构成环就抽象)。然后好像是个弦图啥的,还有个mcs算法,都没看,先咕。

这类题发现点数少,可以枚举几个,然后再在某范围枚几个,在通过一些信息快速得到剩下的。如本题与CSP2022T1。

没看懂复杂度,明天写题解。

5.2 NOI2023训练赛14

100+100+30+15 萎了

下次一定要先写再想!发现每次先胡完的场分数都不堪入目。

T1

是个sb题,就是画一画就发现是向下二次函数的min与向上二次函数的max的中间部分。发现是单峰,三分一下就结了。

但是也有其意义。发现如果是spj,那么输出就尽量多输几位,防止四舍五入寄掉。考试时不要慌,我发现精度爆炸就死磕,然后就导致整场的失利。然后三分可以换为mid+eps,mid-eps比较的求导。

T2

其实这才是罪魁祸首。所以下次第一步想思路对不对,再肉眼观察,再扔几个死角,然后马上调转枪头写对拍不要犹豫!

所以我写的是Trie树上向儿子跳的倍增表,然后用类似ODT思想处理区间覆盖,很简单的思路。但是多了一个log,正解就把向儿子跳倍增表理解为直接预处理(因为一个点,深度固定,从它开始走要走的字符数固定,故可预处理),但是感觉细节比倍增多

打比赛时积极一点,不要像个什么一样颓然。

T3

想到了PAM可以切但是忘了PAM。QAQ

同时不会LCT,摆了。

PAM不可以全局-=‘a’,可能a减为0难与边界0区分。

T4

神仙构造,下次记得暴力打表。

5.3 NOI2023训练赛15

100+50+71+20 直接爆零

FJOI真的很厉害,我谢谢出题人。

T1FJOI2003 T2FJOI2017 T3FJOI2004 T4FJOI2016

所以可以发现FJOI甚至自己搬自己的题,T1又在FJOI2015闪现。

T1

比较有意思,但是做太慢了。首先思路不要死,推corner case时思维要活,在感觉形成一种认定是要努力尝试构造反例。还有高精可以压位不要忘了。

T2

又是lyndon,迟点再学。

注意要尽量打部分分,相信自己的常数,n^3过一万。

T3

这个写不出来真的是实力问题,菜就是菜。

所以朴素的区间DP是朴素的。然后可以发现真的非常难用数据结构结构啥的去维护。此时应当思考决策单调,然后猜猜,然后大概证一下就发现了。甚至因为左右都有决策单调,所以不用斜优。

T4

假题,受不了了。

5.4 NOI2023训练赛16

70+100+20+45 最后一次,也是最狼狈的一次

明明这么接近rk15的目标,却因不好使的脑子,唉。

T1

把我干沉默了,想bitset,最短路啥的想进去就出不来了。所以正解就是发现,对于数对(a,b),a走一步,b走两步后的新数对也是满足条件的。然后一个bfs就好了。要预处理b走两步能到的点,不然复杂度不对。

回来说我,写了bitset维护走n步与2n步能到的点,然后强行或到ans里,考虑可能在两个环里转圈圈,然后就是n可以卡到lcm二者环长,所以总复杂度n4/w,非常败北,DAG是正确的n3/w。然后卡了下循环次数,跑了70pts。考后发现再卡一下就100pts了!!!!!气死我了!!!所以真的是脚造数据,最高9000000的上界给它造成50真的是伞兵,受不了了!!

T2

还好写出来了,不然真就爆零了。所以就是一个bitset来优化转移过程即可。

T3

不会,好像很神仙。

T4

写了bitset跑路。一天三个bitset不愧是我。

T0

也就是D2T4,光荣地发现我不会。

所以就是因为区间长度等于最大减最小加一,所以就是枚举右端点,然后单调栈,再加上用线段树维护全局最小和出现次数。

nfls 7.7-7.22 集训记录

NOI2023-div2模拟赛53

100+100+100 rk1

T1

考场上用了先建树,再树剖+线段树的方法,两个log做法。也可以lct或全局平衡二叉树优化一个log。

题解是考虑染一条边时,将两侧的点合并,那么就是把儿子合到爸爸上,然后把儿子对应子树的每个点dep–,用一个树状数组维护,然后询问时depx+depy-deplca*2即可,O(nlogn) 。

T2

典的SA,略。

T3

考虑我们交换时,必然时在一个环上换。

最优时,也就最多少1,这个环上的点若编号不连续,那么必然至少多走1(因为至少走max-min),必不优。

所以为一个连续段,在这个段中冒泡排序,由于最优时最多换n次,再加检查是否已排好的n次,所以共O(n)。

NOI2023-div2模拟赛54

95+100+40 rk4

T1

首先固定左端点与右端点,考虑时一个d-v的一个凸函数,然后让这些做个凸包。考虑对于较大的右端点的函数,由于可选的节点变多了,所以对于一个d必然斜率更大,所以用二分+主席树算出与原凸包交点,然后更新凸包即可,凸包用一个类似ODT即可。

总共 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n),但是常数大。可以考虑把二分与主席树合并变成主席树上二分。但是凸包对应了若干树,怎么办呢?可以先二分出点位于哪个段,然后一个段对应一个主席树就可以二分了。怎么找是哪个段呢?可以找出每段的最左点,然后把上一个区间都推平成这个值,然后用这个扁平的线段树来二分即可,正确性显然。 O ( n l o g n ) O(nlogn) O(nlogn)

题解是发现左侧端点对应的右端点有决策单调性,然后就分治 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)

详细写下分治,就是求出mid对应rmid,然后mid左侧都小于rmid,右侧大于rmid,然后分治下去就好了。

T2

就是一个(max,+)矩阵+线段树。

T3

首先先模一个2^m,然后把它根据二进制拆了。一个二进制位对应树上的一行,我们就是要求出每个点还能操作几次,发现显然有c[rt]=min(c[ls],c[rs])+(abs(c[ls]-c[rs])?1:0)。然后从下往上,碰到有效的一行就c[rt]–,ans++。

NOI2023-div2模拟赛55

100+0+0 rk31

T1

最短路DAG建出来正着反着跑两次拓扑就好了。注意long double可以处理到1e300左右,只不过精度不对,但是相对误差题中绰绰有余。

T2

这题超级有意思。考虑下一个加入的点为x,撤销了点y,下证明相当于回到了y-1的状态+x的新状态。考虑如果x到y中有一个活动点z,下文<>=指向级别,如果z=x,那么z如果想撤y之前的点,显然一定先撤y,所以z只会撤y-x中的点,所以与y之前的段无关,而x之后的点想要撤z必然先撤x,所以z与x之后的段无关,所以在x活跃时可以直接移除,同时y也移除了,所以得证。

然后考虑维护,可以直接主席树+线段树上二分得到每次撤的点并运用结论来继承。

其次可以考虑到实际上构成了一个树形结构,可以考虑在链上倍增找到撤的点,可持久化就对应了支出一个支链,只有500B。

T3

考虑树分块+bitset。首先如果只有bitset的话就是每位表示这种颜色出现了奇数次还是偶数次,然后两点到根的bitset的异或就是路径的bitset,考虑这里面1个数是否为路径长度即可。考虑减少bitset个数,我们可以撒一些关键点,然后从每个点向上走直到关键点,然后就好了。撒点可以随机撒点,也可以根据dfn序考虑每个点,从每个点向上走 n \sqrt n n 步看看有无关键点,若无则当前变关键点。共 O ( n n + n q w ) O(n\sqrt n+\frac{nq}{w}) O(nn +wnq)

NOI2023-div2模拟赛56

100+100+20 rk4

T1

给出两种做法,第一种是考场写法。首先变问题为 f i = m a x 0 ≤ l < i ≤ r ≤ n 且 L ≤ r − l ≤ R ( s r − s l ) f_i=max_{0\leq lfi=max0l<irnLrlR(srsl)。从后往前考虑,那么我们考虑如何使得一个点被限制在l到r中,那么就是每次扫到一个点,就把它为右端点的所有区间加入,这样又有扫描序,所以就满足了i<=r,再思考满足l s r s_r sr),一种有初始值( s l s_l sl),然后求其一个区间内差的最大值,发现是可以维护的,实际上就如同contest816T4的trick就可以了。

另一种是题解做法,就是这类题由于有一个区间,自然想到了分治然后区间合并,就是左边每个为左端点的最大值(拆为delta s然后st表)的一个前缀来求出左半边每个点作为i而且lr满足分治的max,同理右边每个为右端点为最大值(st表)的一个前缀求出右半边每个点作为i的max。

T2

写过,点分树从根开始跳重心的写法略了。

还有一种是题解做法,结论重心就是满足子树大小>= ⌈ n / 2 ⌉ \lceil n/2\rceil n/2的最深点,也即dfn序最大点,因为子树大小满足那个就是父亲满足条件,而最深就说明没有一个儿子子树大小>= ⌈ n / 2 ⌉ \lceil n/2\rceil n/2,那么儿子就满足了条件。所以找重心可以直接线段树上二分,而之后的询问值就是contest872的trick。

T3

感觉这种分讨题没什么扩展价值,而且超出个人能力,所以略去分讨过程,就是写一个思路。

我们看到这种题,可以想很多,但是个人感觉这题DP形式非常隐晦,这是一种以某种关键点作为状态,然后从关键点的性质出发来简化问题的题。首先肯定想到以棋盘为DP从左向右DP,但是发现树上有哪些点用过,又有哪些点应该用等等,都没有办法搞出来。所以我们考虑在树上DP,那么在棋盘上构成了一团说不定更有可能来维护,所以最后想到了这个状态,dp2在某种意义上为dp1服务。

NOI2023-div2模拟赛57

100+100+10 rk6

T1

就是考虑当两者初始点都确定时,考虑两者最优时的策略,一波分析之后发现当黑客选定x时,最后价值就是所有过x的长度满足要求的区间和的min,然后用一个线段树做一下就好了。

T2

考虑一个显然的trick,就是在可以选的两个之间连边,然后边的方向就是选哪个。

所以只有基环树情况可以,然后基环树有两种选择方式,两种扔到DP里,先默认小的一种,然后物品为大-小,所以就变成了boolDP,用bitset优化。然后再考虑所有物品体积和有上界 O ( 20 n ) O(20n) O(20n),接下来二进制分组就 O ( n n / w ) O(n\sqrt n/w) O(nn /w)

考虑二进制分组,有两种方式。一种是拆分后的新物品加入到后面物品的桶中。这一种最后每个位上最多2个物品,所以物品总共只有 O ( n ) O(\sqrt n) O(n )个,然后复杂度就对了。还有一种是新物品不加入后面物品的桶中。我们尝试构造一种下界,对于第i种物品,我们有 n / i \sqrt n/i n /i个,那么下界就是 ∑ i = 1 n l o g ( n / i ) = O ( n l o g n ) \sum_{i=1}^{\sqrt n} log{(\sqrt n/i)}=O(\sqrt n logn) i=1n log(n /i)=O(n logn),最后多了一个log。后一种在每种物品也有价值时也适用。

T3

考虑只有1和2的时候,就是在12交错的段,如果长度为偶,那一侧全1一侧全2,否则全部同色。然后我们枚举k,把>=k的染2,另一者染1,然后就典了,ans为max(每种情况操作次数)。至于答案,我们考虑每个点只会变一次色,所以用一个set维护11,一个维护22,就可以暴力并查集染色就好了。 O ( n l o g n ) O(nlogn) O(nlogn)

NOI2023-div2模拟赛58

100+0+0 rk48

T1

就是典中典的bfs建kruskal生成树。

T2

考虑这个是模拟费用流,我们看图。

抽象题意就是选出若干天,每一天x对应的任务有 x ≤ t i x\leq t_i xti

S流向每一天,然后每一天流向T,后者有一个费用,每一天流向下一天表示这个小于等于号,然后是最大费用流。为了方便,我们让左侧边流满,然后每一天多连出一条0费用边表示弃而不用,然后对于右侧边,为了方便就拆成若干点使得每个点连向T只有一条边。

考虑加边,发现就是一个找负环的过程,这是由于上述操作下来已达最大流,就没有增广路了。考虑一种是拿时间更早的换,这里用线段树区间max即可,另一种是拿时间更迟的,我们需要对于中间这条路,用线段树维护每条边流了几次,然后线段树上二分出最远可换边,然后线段树区间max,二者取优。

考虑删边,发现就是找一条费用最小的,从这条边起点流向终点的流来替换。类似加边情况的操作,分更早和更晚来贪即可。

O ( n l o g n ) O(nlogn) O(nlogn)

T3

考虑是每个边按权值逐一加入,在每个点不是割点的瞬间计算答案。

考虑模拟一个类似tarjan的过程,我们建成一个圆方树,一开始都只是圆点,这里的建树是最小生成树。然后每次相当于把圆方树上的一条路径的点合并成一个新方点,我们考虑这条路径最浅点是否为圆点。我们用一个并查集表示方点的儿子,同时方点自己记录一个父亲,圆点有一个初始父亲。如果是圆点,那么考虑建出一个新方点,然后把这条路径方点和圆点的并查集指向它,同时这个方点的父亲显然是那个圆点。如果是方点,那么考虑把这条路径上的方点圆点并查集指向它,它的父亲不变。

考虑更新度,第一,就是一个圆点x为圆点y的父亲的话,路径并会使y指向方点,所以x的度减一,第二,建出新方点连向父亲时,要使父亲度加一。

考虑怎么挖出路径,我们可以维护出每个点的深度,这样子就可以一步步向上跳来找。考虑路径合并时,并不影响两个点的关系,也即dep小的始终在上面,所以可以不用修改dep,而用初始dep来做就可以了。然后为了得到方点的dep,我们可以把圆点dep都变两倍,这样方点dep就可以插入其中。

考虑分析一下复杂度,因为一个路径上方点数不超过一半,所以已经被合并了的点(归于一个方点的圆点)数量就不超过一半,而每个点至多合并一次,方点每次最多出现一个,所以分析下来每次路径经过点数和还是 O ( n ) O(n) O(n)的,再加上并查集按秩合并,那么复杂度显然 O ( n α ) O(n\alpha) O(nα)

NOI2023-div2模拟赛59

100+76+0 rk7

T1

首先第一问是可以树形DP直接做,比较简单。然后考虑使用树剖时,就已经有答案上界为log,那么我们可以多一维维护当前子树答案,所以就 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)。然后写完发现可以前缀和优化一个logn。

T2

我们考虑暴力做可以有 O ( n m 2 ) O(nm^2) O(nm2),单点修改时线段树+蒙日矩阵乘法可以 O ( m 2 l o g n ) O(m^2logn) O(m2logn)

第一个想法是线段树,但是空间不够。

第二个想法是分块,但是没有卡常卡过。

然后题解是线段树套分块,块内暴力,外面线段树,这样子就可以灵活调整时间与空间,常数也较小,可过。

T3

发现是一个分类讨论大DP,不想写了,去看题解吧。

NOI2023-div2模拟赛60

100+0+0 rk11

T1

挺厉害的。考虑以栈编号为扫描线,用一个线段树维护时间一维表示元素个数。然后操作一二是容易的,为单点加,考虑询问。我们可以知道这就是在二分一个位置,使得这个是最靠右的,与起始点(当前时间)一段所有的元素个数为k的。然后这个位置的时间的操作就是答案,可以线段树二分解决。 O ( n l o g n ) O(nlogn) O(nlogn)

T2

感觉十分妙。

我们有n个数,也即n个限制。我们从低到高枚举首项的每一位,枚举了最低位,就先把满足了条件的限制去掉,然后每个限制形如“我是第i位,需要j”,我们可以发现这里i的最低位并不影响高位枚举,所以可以把除去最低位剩下的相同的限制合在一起,变为"我是第i位(去了最低位),需要j1,j2,……"。然后显然在枚举了5位之后限制就变成了一个,考虑怎么做,显然就是j从小到大(注意处理前导0)排即可。这里还有一个细节,就是在枚举时可能所有限制都满足了,那么我们还要看一下枚举的有没有前导0,如果有那要舍。

T3

感觉这道题圆方树套线段树很难做。

考虑暴力(值得学习的bitset)。我们首先建出一个圆方树,然后这里有一个优秀性质,就是如果是一个环的话,在圆方树上一定是走一个前缀或者一个后缀,所以就可以对每个点预处理出来最长/最短路要经过的点,放到bitset里。然后操作1和2就是一个异或操作,操作三就是dfn序上的一个区间,所以可以左移右移或者与上一堆1之后count。空间不够,考虑相邻只会改一个位置,所以可以每次不新建一整个,而是新建一个块,这样空间 n n / w n\sqrt n/w nn /w,可过。

还有一种是类似圆方树建树,不想写了,扩展性不大。详见《某静态的超仙人掌》(封面有点可怕)。

NOI2023-div2模拟赛61

没打。

T1

就是从大到小做,然后去去重即可。去重具体就是每次只有每种颜色最大的计算,然后如果某种颜色曾经和谁搭档过,就强制不能选那个颜色(具体的感觉像是以每种颜色最大的为关键点,每个点和最近右侧合作点连边成一个森林,加一个超级源点就成树,然后有一个子树中的颜色不能选,可以树上DP)。

T2

有了结论就比较简单。

一个常见的结论,这个值一定是一条dfs树上简单路径再异或若干个环。这是显然的,可以走到一个环上再走回来,会发现只多了一个环的权值,所以可以放肆加环权。手玩发现不在dfs树上的简单路径都可以由一条dfs树上的通过异或环来互化。

考虑把删边过程反过来,依次加边建出dfs树。考虑边加边边算答案,如果加入了树边,那么就把新增的路径值加入。如果加入了非树边,就把环权压到bitset里。考虑答案就是树边乘上bitset有效值的二次幂。考虑可能有两个树边通过bitset可以互化,所以要去重。具体就是发现可以互化的,那么经过bitset得到的最大值一定一样,所以全部转成最大,然后去重(用set)。在bitset新增元素的时候就全部重算一遍(只用和新增的数异或下取最大)。所以是O(nlogn)。

T3

考虑我们枚举终点t,以t>s为例。可以知道[1,s]和[t,n]一定都走了两次,只有中间可能少一点。考虑中间走三次出现是由于向左走,所以就要尽量减少向左走。我们就在[1,s]和[t,n]中尽量向左走,然后剩下的次数k,就是选中间的前k小之和,用主席树维护即可。显然这个最小,但是要证明可达性。考虑构造,如果在i,i+1和i+2之间的是向左走,那么我们就跳到i+j,使得i+1-i+2-i+3-……-i+j-1之间都是向左走,i+j-1-i+j为向右走,之后一路向左再向右即可。但是如果t-1-t是向左走的怎么办,这就不可能终点是t了。我们发现这样子不妨将t左移变为t-1或者更左,可以发现这样子就满足了我们的移动,所以不妨这么算,反正只是不满足假设,并不与题目要求冲突。

nfls 8.1-8.20 集训记录

NOIP2023训练赛1

0+100+100+0 rk30

T1

dfs简单题,但是赛时被ub了。

T2

AC自动机+线段树简单题。

T3

考虑容斥不合法位置,具体就是枚举左端点w,然后左端点对应序列钦定里面的有几个位置对应的数不合法了,我们设计状态 f i , j f_{i,j} fi,j表示最后一个不合法的是i,右端点是j,考虑从 f k , ∗ f_{k,*} fk,转移到 f i , ∗ f_{i,*} fi,,我们考虑对于其他的要求k对应位置在i之前,这个的概率是1/2,所以总概率是 1 2 j − w \frac{1}{2}^{j-w} 21jw,的所以右端点到i的期望距离是O(1)的(一个等比数列的和)。然后暴力枚举w,i,j,k,复杂度就是O(n^3)的。

T4

我们考虑对于一个点它的子节点的等价类是p1,……,那么方案数就是这些的乘积。我们考虑加入一个点,最多引入logn个新的同构对,这是由于同构的话需要两个部分,那么sz->sz*2,所以是log的,我们暴力找到最浅的x的祖先使得 s z f > = s z x × 2 sz_f>=sz_x\times 2 szf>=szx×2,然后判一下f,再找到一个 s z f f > = s z f × 2 sz_{ff}>=sz_f\times 2 szff>=szf×2,然后以此类推找到log个分别用树哈希判一下就好了。注意还需要把x的所有祖先的同构关系去掉。我们用线段树+树剖类似ddp维护哈希值。

这里给出一种比较正确的哈希,是 f x = g ( d e p x ) ( 1 + ∏ f s o n ) f_x=g(depx)(1+\prod f_{son}) fx=g(depx)(1+fson)(g是随机映射)。

NOIP2023训练赛2

100+100+60+55 rk5

T1

倒序用并查集维护即可。

T2

考虑有用的是选出若干行若干列构成的子矩阵,我们考虑对于行相当于 ( x + y ) n (x+y)^n (x+y)n展开式,其中x表示i+1,y表示不变,那么可以知道x对应的幂次对应的系数是一个组合数,然后有kummer定理知道,当且仅当 x & n = = x x\&n==x x&n==x时这个二项式系数模2为1。所以我们考虑对于位置(x,y),必须有 x & n = = x x\&n==x x&n==x y & n = = y y\&n==y y&n==y那么这个点的才被记入,所以考虑把这个点加入到x|y对应的表里面,对于二进制每一位看作一维,做高维前缀和。

T3

分为两种情况,一种是有一个集合为0,那么我们把没用的都塞到那里,答案就是选最长的k-1个区间的长度和。

另一种情况,我们考虑对于x和y,有y包含x,那么显然要么y单独变成一个集合,要么直接丢掉视为不存在这个区间。对于前者,我们考虑首先x肯定不与y组成集合,另外,如果有一个区间z,然后有x+z和y,y+z和x两种情况,我们考虑由于不会有交为空的情况,所以前者答案是 r z − l x + r y − l y r_z-l_x+r_y-l_y rzlx+ryly,后者是 r z − l y + r x − l x r_z-l_y+r_x-l_x rzly+rxlx,所以后者优,其他情况可以类似分析出来,这是由于r一定是正贡献,l一定是负贡献,而y的r大l小,所以一定自成集合比较优。所以我们对于包含了其他区间的区间,我们剔除出来,计算出选x个的最大值,然后对剩下一部分dp,最后(max,+)卷积一下就好了。考虑dp,由于左右端点都是单调递增,所以设 f i , j f_{i,j} fi,j表示,已经有i个集合,dp到了第j个区间的最大值,然后一次肯定是选一个区间转移过来,故有 f i , j = m a x ( f i − 1 , k + r j − l k + 1 ) f_{i,j}=max(f_{i-1,k}+r_j-l_{k+1}) fi,j=max(fi1,k+rjlk+1),用一个前缀优化即可,O(nk)。

赛后有人给出了更优解法。我们考虑第二部分,每个的区间形如 r − l r-l rl,我们考虑一开始所有点自成集合,然后可以合并相邻的,考虑假如合并[i,j]和[j+1,k],那么贡献的减小量就是 r j − l j + 1 r_j-l_{j+1} rjlj+1。由于我们不用考虑和0取max的情况(这一情况包含在情况一),所以这样子是合适的。取出所有这样子的,然后排序从小到大减就行了。

T4

我们考虑背包的状态太多了。发现由于是乘积,所以只要记录再乘多少就会爆炸,也即 ⌊ m s ⌋ \lfloor \frac{m}{s}\rfloor sm,发现这个一共就只有 O ( m ) O(\sqrt m) O(m )个。但是发现这个东西支持单点加,但是不支持dp数组合并。由于有杂题3的经验,我们考虑点分治,就是一定经过分治中心的结果,然后在dfn序列上dp,有两种,一种是从x+sz[x]转移过来,表示x以及这个子树不选,一种是从x+1转移过来,表示x选。剩下就不难了, O ( n m l o g n ) O(n\sqrt mlogn) O(nm logn)

NOIP2023训练赛3

100+100+80+20 rk3

T1

我们分类,一种是x到y是过1的,一种不过。后者处理是容易的。前者我们可以考虑前序后序dfn然后用一个st表,就O(nlogn)了,常数小可过。也可以在这个序上面dp,就O(n)了。正解是对于每个i求出 p i p_i pi子树内除了 p i p_i pi到i( p i p_i pi是1的儿子,且i在 p i p_i pi的子树内),剩下部分的最值,这个可以直接dp出来,其实和我的序上dp一样。

T2

首先运用《某静态的超仙人掌》trick,把它压成树。具体就是对于一个环,我们把深度最浅的点和剩余点连边。然后运用线段树合并维护信息,线段树那维维护颜色权值在某一区间中时,偶数个数和奇数个数,合并,加入,查询都是朴素的。

T3

这题比较神秘。

我们考虑倒序。可以画出一个折线,这个折线不受上下界束缚,接下来枚举t然后计算有无解。如果没有超过界的话,那么显然有合法解。否则我们取出最后一个超过界的地方,假设是超了max的界,那么显然,如果这个点之后没有碰到0的话,那么最后得到的东西一定

考虑怎么得到第二问的结果,有两种方法。一种是二分初始值x,找到最终结果<=v2的最大x就是答案,正确性是显然的,因为对于 x > = y x>=y x>=y v 2 x > = v 2 y v2_x>=v2_y v2x>=v2y。第二种是考虑逆推这个过程,维护只有后x个操作的情况下,初始的合法区间,那么操作就相当于区间平移或长度加1,倒推回去即可。

T4

我们首先在每个字符串结尾加上"$",这样在字典树上就没有祖先儿子情况了。接下来考虑对于任意一种dfs序都有 W ( Q ) = W ( P G ∗ ) W(Q)=W(P_G^*) W(Q)=W(PG),考虑暴力怎么做。我们从大到小枚举任务,然后判断行不行,具体就是x,y,lca要满足x到lca的路上x对应祖先p要是 f a p fa_p fap对应的儿子dfs序中最迟的,y同理是最早,然后在lca处两个对应的 p x p_x px, p y p_y py要用链表连成前后关系。对于最迟最早那么就判一下是否已经有最迟最早,或者链表上接了前驱后继,对于能否接,就判断是否已经有最迟最早,或者链表上接了前驱后继,反正分讨一下就好了。考虑分析复杂度,我们路径压缩,把只有一个儿子的点压掉,那么想要深度最深,就一定是一个左偏二叉树,而这种极端情况的深度是 ∑ l i \sqrt {\sum l_i} li ,所以压缩后暴力做复杂度是 O ( n n ) O(n\sqrt n) O(nn ),可过。

NOIP2023训练赛4

100+70+100+0 rk18

T1

可以把一个连通块里面度为奇的点连边,然后对于每一个连通块跑欧拉回路,然后再把最开始加的这些断掉。

T2

建几个字典树,然后优化连边,然后2-SAT即可。注意要搞清楚2-SAT的定义,2-SAT最好从原本定义出发,而不要乱触类旁通把连边乱搞,就是经典的套上去,否则非常容易爆。

upd:可以证明暴力连边的复杂度是线性的。

T3

换根+线段树维护所有点到根的距离,然后用dfn搞一下可以走的点就好了,简单题。

T4

首先把整个图转45度,然后就是横着移和竖着移,考虑逆过程,然后发现是有单调性的,也即如果一开始x在y的左下角,那么永远x在y的左下角,可以树状数组+二分或者树状数组上倍增解决。

NOIP2023训练赛5

100+100+100+40 rk3

T1

考虑对于每一个位置i,和每一个质数p,求出 f i , p f_{i,p} fi,p表示i可达的点中第一个有质因子p的位置, f i , p f_{i,p} fi,p可以从i的每个质因子x第一次出现的位置 w x w_x wx对应的 f w x , ∗ f_{w_x,*} fwx,转移过来,这个第一次出现位置可以从后往前扫,维护w,每次扫到i的时候,处理完 f i , ∗ f_{i,*} fi,后,把所有的 w x w_x wx赋为i即可,答案的处理是容易的。复杂度是 O ( n ∗ c n t p ( n ) ∗ w ( n ) ) O(n*cntp(n)*w(n)) O(ncntp(n)w(n)),可过。

T2

可以BM直接切掉,但是我不会。

可以考虑 m = 6 m=6 m=6的时候是满足费马小定理的,模完再快速幂即可。其余情况暴力快速幂。

可以搜出来可以从000000转移过来的状态个数,这个是20,所以我们把空间压一下就可以过了。还有更加直接的,在矩乘的时候特判一下 i f ( a [ i ] [ j ] ! = 0 ) if(a[i][j]!=0) if(a[i][j]!=0),这样就可以变快很多,同时再一些常数优化(快速幂以10为底)就可以过了。

这种矩乘里特判的思想是重要的,可以在没时间压状态的时候骗分。

T3

显然答案要么1,要么2(对顶栈),两种情况构造一种方案即可,具体不想写,并没有营养,可以看题解。

T4

感觉是见过的dp里面比较难的一道。

首先问题相当于求每个S的最大独立集大小之和。

考虑lca深度从大到小考虑,选了一个就相当于把lca对应的子树整个剔除,然后可以加入的充要条件是两端点尚未被剔除。考虑怎么dp,设 f i , j f_{i,j} fi,j表示第i个节点的子树内,i所在未被剔除的连通块大小为j的S种数,特别的, f i , 0 f_{i,0} fi,0就表示有一条lca为i的路径被选择了。

首先我们分析一下, f i , j f_{i,j} fi,j的真实含义就是f(S)向S的映射,说的清楚一点,就是当f(S)满足i子树内,i所在未被剔除的连通块大小为j时,S的个数,也就是说 f i , 0 f_{i,0} fi,0就表示存在一条过i的路径在这个最大独立集里面时的S个数。

特别的,首先这条路径是在S集合里面的,然后考虑i子树外的路径尚未考虑,如果有一条子树外路径企图将这条路径取而代之,那么显然答案首先会减1,同时外面也最多只多一条,也就是答案之后最多加1(这是因为过i点的子树外路径最多只能有一条在最大独立集里面),最大独立集并没有变大,同时, f i , 0 f_{i,0} fi,0隐含了如果只考虑i子树,那么这条路径位于S的最大独立集里面。所以接下来可以考虑用 f i , 0 f_{i,0} fi,0来计算lca为i的路径对于答案的总贡献。具体来说i子树外的路径还是可以任意选的,所以要乘上 ( n − s z i ) 2 (n-sz_i)^2 (nszi)2,所以 a n s = ∑ f i , 0 ( n − s z i ) 2 ans=\sum f_{i,0}(n-sz_i)^2 ans=fi,0(nszi)2

接下来考虑 f i , j f_{i,j} fi,j如何转移。首先 f x , ∗ f_{x,*} fx,的初始化是考虑 ( x , x ) (x,x) (x,x)这条路径选不选,所以 f x , 0 = f x , 1 = 1 f_{x,0}=f_{x,1}=1 fx,0=fx,1=1。接下来只用考虑 f x , ∗ f_{x,*} fx, f s o n , ∗ f_{son,*} fson,的合并。首先考虑 f x , 0 f_{x,0} fx,0的转移,我们发现这里 f x , 0 f_{x,0} fx,0的含义,就是存在一条lca为x的路径,同时“这一条路径是不过son子树的”,所以无论新增的路径怎么选,那么把这条“lca为x的路径”选到最大独立集里面都不会劣,这是由于这条路径和son子树内的新增路径没有“冲突”,而把新增的lca为x的路径和它替换显然答案不会更优。所以有转移 f x ′ , 0 = f x , 0 ∗ p w [ s z s o n 2 + 2 s z s o n s z x ] f_{x',0}=f_{x,0}*pw[sz_{son}^2+2sz_{son}sz_x] fx,0=fx,0pw[szson2+2szsonszx],接下来pw表示 2 p 2^p 2p,注意此处还没有进行 s z x + = s z s o n sz_x+=sz_{son} szx+=szson,这里 s z s o n s z x sz_{son}sz_x szsonszx有2的常数是因为可以左端点在x里面右端点在son里面,也可以反过来。考虑其他的转移,具体就是枚举i和j表示要合并 f x , i f_{x,i} fx,i f s o n , j f_{son,j} fson,j,然后考虑过x的路径是否选,首先与二者冲突的路径可以随便选,选了也不会使最大独立集变大,具体就是可以乘上 p w [ 2 s z x ∗ s z s o n − 2 i j ] pw[2sz_x*sz_{son}-2ij] pw[2szxszson2ij],然后考虑没有冲突的,一旦选了一条,那么就会使最大独立集大1,那么就是转移向 f x ′ , 0 f_{x',0} fx,0了,如果一条都没选,那么就是转移向 f x ′ , i + j f_{x',i+j} fx,i+j,所以就是 f x ′ , i + j = f x , i ∗ f s o n , j ∗ p w [ 2 s z x s z s o n − 2 i j ] f_{x',i+j}=f_{x,i}*f_{son,j}*pw[2sz_xsz_{son}-2ij] fx,i+j=fx,ifson,jpw[2szxszson2ij] f x ′ , 0 = f x , i ∗ f s o n , j ∗ p w [ 2 s z x s z s o n − 2 i j ] ∗ ( p w [ 2 i j ] − 1 ) f_{x',0}=f_{x,i}*f_{son,j}*pw[2sz_xsz_{son}-2ij]*(pw[2ij]-1) fx,0=fx,ifson,jpw[2szxszson2ij](pw[2ij]1)。这些转移后 s z x + = s z s o n sz_x+=sz_{son} szx+=szson即可。

具体实现建议看代码,然后从这个感性理解出发来理解。

NOIP2023训练赛6

100+100+100+80 rk4

T1

对于每一个分开计算,简单题。

T2

考虑分情况,如果 n % 2 = = 1 n\%2==1 n%2==1 m % 2 = = 1 m\%2==1 m%2==1,我们可以列式子,设每个的终态是x,那么就有 ∑ 2 ∣ (̸ i + j ) ( x − a i , j ) = ∑ 2 ∣ ( i + j ) ( x − a i , j ) \sum_{2|\not (i+j)}(x-a_{i,j})=\sum_{2|(i+j)}(x-a_{i,j}) 2∣(i+j)(xai,j)=2∣(i+j)(xai,j),考虑这个时候x是没有办法消完的,可以直接解出来一个,然后check一下。对于n与m有一个是2的倍数的情况,考虑是可二分的,所以就可以check然后二分。考虑怎么check,发现这个是一个二分图,可以连边跑最大流来check。

T3

考虑把这个过程逆过来看。我们用[l,r]表示最后答案是这个区间的max,发现每次如果有 l [ i ] ≤ l ≤ r [ i ] l[i]\leq l\leq r[i] l[i]lr[i],那么 a [ l ] a[l] a[l]这个位置会变成 m a x i = l [ i ] r [ i ] a i max_{i=l[i]}^{r[i]} a_i maxi=l[i]r[i]ai,所以可以视为[l,r]变成了[l[i],r],所以考虑对于l和r分别求出最终的值,然后区间查询最大值即可。我们考虑怎么求出l和r最后的值,以l为例。我们找到最靠右的满足 l [ i ] ≤ k ≤ r [ i ] l[i]\leq k\leq r[i] l[i]kr[i]的区间,这个怎么做呢,我们可以开一个可持久化线段树,每次对于[l[i],r[i]]区间赋成k,然后在root[R]上直接单点查询即可。然后考虑对于每个区间i,最靠右的满足 l [ j ] ≤ l [ i ] ≤ r [ j ] l[j]\leq l[i]\leq r[j] l[j]l[i]r[j]的区间,然后说明i可以跳到j,j向i连一条边就形成了一个树形结构,i可以不断的向上跳,直到其父亲的标号 l [ i ] ≤ k ≤ r [ i ] l[i]\leq k\leq r[i] l[i]kr[i]的区间i,然后i在树上一直倍增,找到最浅的满足标号>=L的位置,然后这个位置的l就是所求的,对于r同理。一共O(nlogn)。

T4

考虑怎么暴力,这是比较常见的,就是开一个堆,然后每次取堆顶,输出,然后找到这个排列的合法的最小后继压到堆里面。为了保证复杂度,我们要求每一个排列只有一个前驱,这个前驱就是通过每次交换最靠右的逆序对得到,发现这样子的话就满足了前驱一定比它先入堆,所以这样找合法。考虑有了这个之后来思考怎么找后继,我们发现找到当前最靠右的逆序对位置p(其中p是这个逆序对的左端点,接下来也都这样来表示逆序对),可以发现对于 i ≤ p − 2 i\leq p-2 ip2的顺序对都是不是后继,同时 i = p i=p i=p不是顺序对,同时对于 i > p i>p i>p一定是顺序对且是后继。然后发现 P p − 1 < P p + 1 P_{p-1}Pp1<Pp+1 P p − 1 < P p P_{p-1}Pp1<Pp的话,那么交换p-1和p之后原本p和p+1位置构成的逆序对变成了顺序对,然后p-1和p就构成了最靠右的逆序对,所以当且仅当满足这个条件,那么是p-1合法后继。所以我们有了后继的充要条件,接下来就是考虑怎么判最小,我们通过比较 P i a i + 1 + P i + 1 a i − P i a i − P i + 1 a i + 1 P_ia_{i+1}+P_{i+1}a_i-P_ia_i-P_{i+1}a_{i+1} Piai+1+Pi+1aiPiaiPi+1ai+1来判断大小,所以这个暴力就好了。注意当p从堆里面弹出来用了之后,不仅要压入p的后继,还有考虑压入p的前驱的除了用过的之外的最小后继。

考虑怎么改成满分。我们发现我们可以存前驱的交换位置x,考虑 P i a i + 1 + P i + 1 a i − P i a i − P i + 1 a i + 1 P_ia_{i+1}+P_{i+1}a_i-P_ia_i-P_{i+1}a_{i+1} Piai+1+Pi+1aiPiaiPi+1ai+1在大部分地方都是相同的,只有x的前后几个是不同的,所以可以直接可持久化线段树继承,然后几个单点修改。对于用过的位置和不合法的位置,可以赋成INF,对于用过的位置,就是一个单点修改,对于不合法的位置,考虑可以知道x就是当前的最靠右的逆序对的位置,所以可以做一个前缀赋INF和几个单点修改来实现。然后对于排列长什么样,用可持久化数组解决。所以整个流程就可持久化了,可以过题。

彩蛋:无视了“数据有一定梯度”,没有尝试改变数组大小而是来写题解,痛失rk2.

T3

最长题解警告。(2k)

自己花了一天搞出来的做法,但是比较劣。首先看到的第一眼就想到了先质因数分解拆开,然后就变成了和幂次有关的问题,可以直接dfsdp就可以单次O(约数个数)解决了,大概可以40pts。然后再想了一下,就感觉可以min-max容斥,但是可悲的是这个min-max容斥之后并不好解决。简单的min-max容斥在容斥后会发现每一个人当前未到终点的概率都是一个等比数列,然后乘一起还是等比数列,根据期望拆成每步概率之和,就变成了等比数列求和。但是这里我们发现每个并不是等比数列,根本做不了。于是开始找 p k p^k pk操作n次之后的概率,这里写一下手搓的表:
p 1 : 1 2 n p 2 : 2 2 n + − 1 3 n p 3 : 3 2 n + − 3 3 n + 1 4 n p^1:\frac{1}{2^n}\\ p^2:\frac{2}{2^n}+\frac{-1}{3^n}\\ p^3:\frac{3}{2^n}+\frac{-3}{3^n}+\frac{1}{4^n} p1:2n1p2:2n2+3n1p3:2n3+3n3+4n1
发现规律挺难找的,然后在手搓的过程里面发现对于 1 k n \frac{1}{k^n} kn1的系数之间是独立的,可以一条龙推下去,具体的来说,以 1 2 n \frac{1}{2^n} 2n1的系数为例,发现有:
p 1 : 1 p 2 : 1 ∗ 2 1 p 3 : 1 ∗ 2 1 ∗ 3 2 p 4 : 1 ∗ 2 1 ∗ 3 2 ∗ 4 3 p 5 : 1 ∗ 2 1 ∗ 3 2 ∗ 4 3 ∗ 5 4 p^1:1\\ p^2:1*\frac{2}{1}\\ p^3:1*\frac{2}{1}*\frac{3}{2}\\ p^4:1*\frac{2}{1}*\frac{3}{2}*\frac{4}{3}\\ p^5:1*\frac{2}{1}*\frac{3}{2}*\frac{4}{3}*\frac{5}{4}\\ p1:1p2:112p3:11223p4:1122334p5:112233445
也就是发现是一个连乘式,然后分母逐渐增大,分子永远是分母加一。同理可以发现 1 3 n \frac{1}{3^n} 3n1也是如此,但是分子是分母加二,之后都是如此。这是可以证明的,比较麻烦,这里就略了,发现了这个之后愚钝的我还没有明白,于是关于每个的系数打了一个表。
1 2 k : 0   1   2   3   4   5   6   7 1 3 k : 0   0   − 1   − 3   − 6   − 10   − 15   − 21 1 4 k : 0   0   0   1   4   10   20   35 1 5 k : 0   0   0   0   − 1 \frac{1}{2^k}:0\ 1\ 2\ 3\ 4\ 5\ 6\ 7\\ \frac{1}{3^k}:0\ 0\ -1\ -3\ -6\ -10\ -15\ -21\\ \frac{1}{4^k}:0\ 0\ 0\ 1\ 4\ 10\ 20\ 35\\ \frac{1}{5^k}:0\ 0\ 0\ 0\ -1 2k1:0 1 2 3 4 5 6 73k1:0 0 1 3 6 10 15 214k1:0 0 0 1 4 10 20 355k1:0 0 0 0 1
我只打了部分的表,但是可以说明问题了,除去正负号,第一行是e的一次前缀和,第二行是e的二次前缀和,第三行是e的三次前缀和。那么我再挖掘一下,发现 p k p^k pk 1 t n \frac{1}{t^n} tn1的系数是 ( − 1 ) t ( k t − 2 ) (-1)^t\tbinom{k}{t-2} (1)t(t2k)

然后我们就尝试把每一项的这个等比数列和式乘在一起展开,然后对于每一项是一个等比数列,可以分别等比数列求和。然后我们就用这个方法做,发现如果暴力做的话单次复杂度还是O(约数个数)。考虑优化,这时我发现如果所有的都是幂次都是1,那么约数个数达到了极大,如果有p个质因子,那么就有2^p个约数,但是同时,我们这里等比数列的类型数却只有p个。也就是我们这里每次“卷”上一种质因子后,针对等比数列种类进行一个合并同类项,这个时候我造了几个极端数据,发现这个项数都是<1000的,事实证明在题的数据范围里最劣也是<2000的。所以我们加一个合并同类项,然后卷积,那么单次询问就是O(2000*20),这里2000是项数种数,20是质数种数,但是即为不满,因为质数种数变大就很可能项数总数变小。然后我写了一个用map处理合并的写法,常数太大还是只有40pts。

于是我又开始思考怎么优化。这个时候我发现,由于我们可以抽象成只与幂次有关的卷积(这里不是一般意义上的卷积,但是这样表述比较方便,下文也这样讲),所以考虑幂次数列是不是会比较少。于是感受了一下,发现可以通过搜索到达所有的幂次数列,具体的我们搜 p 1 k 1 p 2 k 2 ⋯ p1^{k1}p2^{k2}\cdots p1k1p2k2 k 1 ≥ k 2 ≥ ⋯ k1\geq k2\geq\cdots k1k2,这里 p i p_i pi表示第i小的质数,可以证明这包括了所有的情况。最开始手捏了一下感觉数列最多10000个左右,事实证明在题设条件里,一共有170000左右的情况,所以其实也是很多的。但是dfs有一个好处,就是我们搜下去一层的时候可以卷上一个,然后可以继承当前结果,类似(contest 861 DP专题 T1的想法),那么就不用对于每一种情况O(2000*20)的做,而是O(2000)了。

考虑怎么dfs,我们开层数个map,然后每次下去一层的时候使用上一层的map卷上当前的幂次,然后得到当前层的map,再用当前层的map计算出答案即可。考虑怎么储存答案,我直接暴力用一个map<__int128,long long>在 p 1 k 1 p 2 k 2 ⋯ p1^{k1}p2^{k2}\cdots p1k1p2k2处储存了,查询的时候质因数分解,排序,然后就得到对应的 p 1 k 1 p 2 k 2 ⋯ p1^{k1}p2^{k2}\cdots p1k1p2k2了。这个在sub3的情况下跑了4s,我直接哭死。

于是开始卡常,大力卡常。首先map实在是太逊了,经过思考,发现可以视为每一项和有序数列卷起来之后合并,那么就是若干个有序数列的合并。我们可以把每一个头扔到priority_queue里面,然后这样子做下去即可。可以从log2000k变成logk,然后就有70pts了。但是sub4就根本跑不动了。

继续考虑卡常。开始思考卷积部分的优化,我们发现大多数的次数都是1,而次数为1的时候,这个卷积这样子跑显然太浪费了。所以我想到可以分成两部分,一边是幂次>1的,一边是幂次=1的,对于前者暴力跑,对于后者我们可以运用组合数等数学知识O(cnt)求出来,然后二者卷一下,这样子效率就高了不少。最后这个大概优化了5倍的常数,sub4跑了5s左右。

不行,还要继续优化。于是我把正负时用的fg改成了±号,多存了几个减少cachemiss,最后取模减少取模次数,同时发现等比数列里面的那个k是<2e6的,于是预处理逆元加快计算,这些使我跑到了4s以内。不行,还要继续优化。于是我开始观察幂次>1和幂次=1的卷积,我发现那个式子是 b ∗ ∑ ( n i ) ( − 1 ) i 1 a ∗ 2 i − 1 b*\sum\tbinom{n}{i}(-1)^i\frac{1}{a*2^i-1} b(in)(1)ia2i11,这里面a和b是幂次>1部分的一些特征量,这里n是幂次=1的项的个数,同时有一个性质就是 a ∗ 2 i < = 2 e 6 a*2^i<=2e6 a2i<=2e6。所以我直接对于每一个有效的a和对应的有效的n,花了 O ( V l o g 2 V ) O(Vlog^2V) O(Vlog2V)的代价预处理了后面sigma的值,这样子卷积部分就加快了。然后就跑到了3s左右。

不行,还要继续优化。于是我在预处理部分只采用了有效的a计算,这部分常数小了20倍左右。然后把各部分的上界卡了一下(埋下伏笔)。同时又处理了一波新加部分的取模和cachemiss,改小了部分计算的常数。最后跑到了2.5s左右。不行啊就快冲过去了,然后我就因为一直卡这道题而头痛,过去摆烂看书了。

看完书想到了一个方法,就是在卡常的时候发现priority_queue卷积部分还是大头,又慢又难卡常,所以最后想了另外一种合并方式。首先这个东西像归并。所以开始思考多序列的归并,然后发现只要构建一个类似线段树的结构,然后叶子放序列,归并上去的话复杂度就是O(需要归并的元素个数),常数只有4倍左右,这个是一个不错的trick,要记住。于是我就写了这个,把多log又常数大的priority_queue换掉了。然后就跑了1.6s,卡到了2s以内。

但是悲伤的是它WA了,发现是读入挂了,开始手写读入。

悲伤的是它又WA了,我捏了几个边角都没用,于是心如死灰写了一个对拍,惊喜的发现根本拍不出错,于是又开始捏边角。最后灵机一动,发现有效状态数不是只有约17000个吗,那么我把它们都输出来就好了呀!这个也是查错的时候不错的trick。然后就发现错误率有1/1000左右,但是由于错误的地方都是前几个质数幂次很高,后面是十几个一次幂的,同时数字很大,由于我是对于 p 1 k 1 p 2 k 2 ⋯ p1^{k1}p2^{k2}\cdots p1k1p2k2里面的k随机,所以这些情况很难随到,很可能不小心给后面的元素赋了二次幂或更高,总之随到的概率感觉上低于 1 / 1 8 18 1/18^{18} 1/1818,而且又不是所有这类数都会hack,所以导致我没捏到。查了一下发现是卡常的时候卡上界,我错误的把sigma预处理部分的上界卡成了maxa,应该是max(a*2^i)。感觉这类问题很难避免,所以就是学一个hack技巧。

最后发现这个改完还是TLE,所以又卡了一遍上界,1946ms擦着边过去了,成功获得最劣解。

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