2017集训队作业
[upd 9.21] 居然是atcoder加胡策,虽然atcoder我已经做完一半了,但我很担心胡策里大家互相伤害啊
[upd 9.23] 补补比较好玩的题的题解吧
[upd 10.6] 做些别的比赛吧,老做atc也很无聊啊
[upd 11.24] 似乎弄够自选题也有些日子了,先更更博客吧
[upd 12.12] 清华集训后浪了整整4天,第五天填填补补算是把13300分弄够了,不过好像还是靠自选题的哎,后面要开始更更题解了
已完成:
atcoder: 101/104
胡策:32.25/52
AGC
[agc001_e]
很漂亮的建模,考虑$i,j$时对答案的贡献$\binom{a_i+a_j+b_i+b_j}{a_i+a_j}$,可以看作是点$(-a_i,-b_i)$走到$(a_j,b_j)$的方案数。最后建出$2n$个点,在网格纸上dp即可。复杂度$O(max\{a_i\}^2)-O(max\{a_i\}^2)$
[agc002_d]
比较容易的cdq分治。
[agc002_e]
很妙的建模。按照从大到小把糖果排个序,第i列上放a_i个糖,把第一种操作看作去掉最左边一列的糖果,第二种看作去掉最下面一列的糖果,这样就可以看作在糖果的点阵上行走。设$f_{i,j}$表示第$i$列倒数第$j$行时先手是否必胜,胜的转移是相邻有负,负是相邻均是胜。可以发现上边界和右边界的情况容易处理,如果一个点是负,显然左下的也是负,边界上显然也不会有连续3个是胜,那么可以发现左下方的对角线的答案是和其边界情况相同的。算出(1,1)对应的边界点,根据上方和右方的点数讨论一下即可。复杂度$O(n)-O(n)$。
[agc002_f]
这么sb的计数都不会了,可以考虑把第一个$0$对应第一个出现的非$0$数字,以此类推。那么假设第$i$个非$0$数字就是$i$,那么要求第一个$1$出现在第一个$2$前,第一个$2$出现在第一个$3$前...以及第二个$1$出现在第二个$2$前,第二个$2$出现在第二个$3$前...的方案数。由于正着搞不好统计方案数,倒着算可以发现当前数最后$k-2$个(如果转移第二个类型的)和其他已有的是独立的,那么dp_{i,j}表示搞定后$i$个的第一个和后$j$个的第二个的方案数,转移直接枚举下一个放哪一种类型即可,答案为$dp_{n,n}$。复杂度$O(n(n+k))-O(n(n+k))$。
[agc003_e]
感觉和最近的一场cf的E很相似啊(而且简单了不少),就是从后往前高,现在问题被拆成若干个$(i,j,k)$:要找第$i$次之后的串中,前$j$个数字,共计入答案$k$次。可以发现每次$(i,j,k)$会变成$(i-1,j\bmod a_{i-1},k)$ 和$(i-1,a_{i-1},k\times \lfloor \frac{j}{a_{i-1}} \rfloor)$,这样二分第一个$j$超过$a_{i-1}$的三元组,把后面的更新了,显然更新完$j$变为不超过$\lfloor \frac{j}{2} \rfloor$,整体就相当于所有的$a_i$下降log次,总复杂度即为$O(n\log n\log max\{a\})-O(n)$。常数优化可以直接枚举$i$,模拟$a_i$下降的过程。
[agc003_f]
如果第k层的块上下、左右都可以接上,那么显然$k+1$层也可以。所以如果上下、左右都能接上,答案为$1$。如果上下、左右都不能,显然为#的数量$cnt$的$k-1$次方。下面假设上下不可以接上,设块与块左右相邻的个数为$ccnt$,原图有$lcnt$行可以左右相接,$f_i$表示$i$层的连通块数,$l_i$表示两个$i$层块左右相接后减少的连通块数,那么有$f_i=cnt\cdot f_{i-1}-ccnt\cdot l_{i-1},l_{i}=lcnt\cdot l_{i-1}$,可以想到用矩阵乘法来优化。复杂度$O(nm+\log K)-O(nm)$。
[agc004_c]
现在彻底不会构造了。
把第一行第一列和剩余奇数行给第一个,最后一行最后一列和偶数行给第二个,这样显然连通且不重复。
[agc004_e]
sb dp题,居然又没想出来。
维护搞完了$[ex-lx,ex+rx],[ey-ly,ey+ry]$的最小值,然后也就知道了边界,扩展一行或一列转移即可。
[agc004_f]
[agc005_f]
这种fft能放F?就是直接考虑不可行的情况,相当于把一个点去掉剩下点在同一个连通块中的情况。最后fft一遍。复杂度$O(n\log n)-O(n)$
[agc006_c]
连这种题都不会做的我...
容易发现对a做一次相当于让$x_a$变为$x_{a-1}+x_{a+1}-x_a$,那么对整个序列差分后整个变换就变成了交换相邻两个元素。根据得到的轮换搞一搞就行了。复杂度$O(n)-O(n)$
[agc006_d]
由于看起来什么性质也没有,只能想到把它二分答案之后变成01问题。假设每次变换后长度不变,最左右的数字变换后为原来位置上的数字。通过找规律可以发现:先把极长的0101...这样的段拿出来,如果左右数字相同,那么无限次变换后会变成哪个数字,否则把整个一分为二,两段上的数字等于他们的端点上面的数字,上述结论均可用归纳法证明。这样每次判定线性扫一边即可。复杂度$O(nlog n)-O(n)$
[agc006_e]
[agc006_f]
对每个弱连通分量独立考虑问题。显然可以去掉若干边后(仍保证弱连通),能给一个连通块三染色,满足只有0向1、1向2、2向0连边,那么我们可以利用归纳法证明所有0都向1连边(1向2、2向0同理):对于一个012都只有一个的图显然可以,再讨论一下每次加入一个和之前连通块有边的点的情况即可证明。如果三染色中只需要两种颜色,那么显然不会再有新边出现。如果原来连通块存在不满足三染色条件的边:那么一定出现二元环,再讨论一下就可以证明这种图中一定所有边都是可以出现的。根据上述3种情况的讨论,dfs一边即可得到答案。复杂度$O(n+m)-O(n+m)$
[agc007_e]
情况太多实在觉得没法贪心,那么就先二分答案,转换为判定问题。然后维护$dp_{i,j}$表示做完第$i$个点,进出的链长分别为多少(尽可能小)(假设$dp_{i,0}<dp_{i,1}$),合并的时候枚举连接这两个子树用哪两条链。但这样会产生很多的合法情况,所以只能每次dp时都拿一个vector存下所有的状态,排序后去掉两个都大于等于前面某一种的情况,由于两条链来自两个子树,所以可以发现最后每个子树这样dp后存的状态数小于等于其较小的一个儿子的状态数的两倍,那么也就是$2^{dep_i-1}$($dep_i$表示以i为根子树内叶子的最小深度)。由于这样求和后是$O(nlog\,n)$的,所以每次dp合并的时候就用2 pointers扫一扫,再利用归并排序把那些没有用的去掉。总复杂度$O(nlog\,n\,log\,MAXANS)-O(nlog\,n)$
[agc008_e]
把一个环分成两种情况考虑:所有都只是下一个或下两个,两种方案都存在。那么对于全部相同的情况,把结果中每个环的大小的个数搞出来,最后对于同一种环大小枚举两个环并成一个的个数,利用组合数算一算即可。
对于两种方案都存在的情况:结果一定只在一个连通块中。选择一个有两个点指向的点为根,去掉他所指的那条边,来决策这些点的次序。如果两个点都指向他的点,必然每个点有且只有一个(不然无解),那么他们的次序就由他们父亲的次序决定。不然讨论一下唯一有指向他的点,如果有一个点指向,那么无法区分次序,答案乘$2$;否则就确定了这两个的次序,dfs继续考虑新的两个点次序(里面有些细节)。最后对于根指向的点,算出他最大的可能次序来判断是否无解,否则如果根指向一个无法确定次序的点,但第$cnt/cnt-1$中有一个确定了,那么答案除$2$。复杂度$O(n)-O(n)$
[agc008_f]
考虑怎么把每种方案弄出最小$d$表示:如果一个执行操作$(x,d)$,结果中他只有一个子树$y$没有填满且其他的子树深度小于$d-1$,那么$(y,d-1)$ 也一定是对的,$(x,d)$就不是最小$d$表示。如果往一个填满的子树移动,那么一定可以用更大的$d$表示,就不予考虑。所以最小表示$(x,d)$的条件是操作完后其子树最大深度(假设以$x$为根)$-$子树次大深度$\leq 1$,用树形dp就可以解决$s$全为$'1'$的点。对于$s$为$'0'$的点,找其深度最小的子树(也就是这个点d值的下限)。复杂度$O(n)-O(n)$
[agc009_d]
把问题变为:给每个点一个标号,要求标号相同的点的路径上必须有一个标号大于他们的点,最小化最大标号。由于答案不超过$log\,n$容易想到状压dp,$dp_{i,j}$表示$i$号点的子树中,状态$j$(表示哪些到根路径上没有点比他大的标号集合)是否能达到。考虑合并的过程,把下面所有子树的每一位数字和加起来,找到最后一个大于$1$的位置后面的第一个为$0$的位置改为$1$,前面全部清零。可以发现对于每个点只要维护一个最小满足条件的$j$即可(利用向前清零的性质可以证明)。复杂度$O(nlog\, n)-O(n)$
[agc009_e]
假设我们知道最后的结果$x=(0.x_1x_2...x_L)_k$,那么显然数组求和$S$必须不超过$n$。如果不超过$n$,构造一个深度为$L$的树,只有每个非叶节点的第一个子节点有孩子,把$k$进制数按位填进去一定能得到答案,所以只要$S\equiv n(mod\; k\!-\!1)$,每次把一个叶节点整成$k$个点一定能得到结果。同样对于$1\!-\!x$也要满足这样的性质(关于$m$)。由于总数与$k$的关系,只要$x$满足取模条件,$1\!-\!x$也一定满足,那dp只要维护当前位的和,再枚举最后一位(便于计算$1\!-\!x$的数位和)讨论一下即可。复杂度$O(n^2)-O(n)$
[agc011_e]
第一想法直接贪心每次去掉一个最大的不下降数字。考虑如何找这个数字:先找到最长不下降的前缀$[1,R]$,再找到其连续相同的后缀$[L,R](L\leq R)$,去掉的数字为$s[1...L-1]+s[L-1]+999...$,这样就可以把$s[1...L]$全部去掉,剩下的部分加1。加速就维护$a[i]\neq a[i+1]$下标的set,每次暴力往后找直到第一个下降的位置,复杂度$O(Llog\,L)-O(L)$,这样居然过了。
看了题解:把每次操作若干个形如$1,11,111,111...$这样的数字,那么$n=\sum\limits_{i=1}^{9ans} (10^{r_i}-1)/9$,则$9n+9ans=\sum\limits_{i=1}^{9ans} 10^{r_i}$这样枚举$ans$,根据数位和即可得出,由于高精度加$9$是均摊$O(L)$,总复杂度为$O(L)-O(L)$
[agc015_f]
丧心病狂的数学题。
很容易考虑到对于数对$(a,b) (a<b,下同)$若满足$f(a,b)=k$,一定满足$a\geq F_k,b\geq F_{k+1}\; (F_0=F_1=1,F_i=F_{i-1}+F{i-2})$。这样就容易算出答案$k$了,显然所有满足条件的数对满足$a<F_{k+1}或b<F_{k+2}$。那么把答案为$k$的数对分成两部分:$b<F_{k+2},b\geq F_{k+2}$。
设一个优秀的k数对$(a,b)$满足$f(a,b)=k, b\leq F_{k+2}$。那么对于任意的一个$b\geq F_{k+2}$的数对都可以通过一次变换变成一个优秀的$k-1$数对。
对于一个优秀的$k(k\geq 3)$数对$(a,b)$,可以利用归纳反证法证明变换一次之后也是优秀的(不妨说我们已经证明了<k的情况):如果一个优秀的数对,变换之后不优秀了,那么变换两次必然还是优秀的,那么在优秀的k-1数对中必存在(x,y)使得他能$x+py> F_{k+1},x+(p+1)y\leq F_{k+2}$。由于优秀的k-2数对(x,y)满足$x\geq F_{k-2},y\geq F_{k-1}$,所以$x+2y\geq F_{k+1}$且只有$x=F_{k-2},y=F_{k-1}$时取等。那么对于$(F_{k-2},F_{k-1})$,反变换得到的最小的非优秀数对为$(F_{k-1},3F_{k-1}+F_{k-2})=(F_{k-1},F_{k-1}+F_{k+1})$,再反变换得到的$b=2F_{k-1}+F_{k+1}>F_{k}+F_{k+1}=F_{k+2}$,与假设矛盾。
引理:$F_{i}\times F_{j} \geq F_{i+j-1} (i,j>0)$,只在$i=1$或$j=1$时取等。
其他的情况下任何一个优秀的$k-2$数对$(x,y)$必然通过某个$(F_{p},F_{p+2})$不停地辗转相加得到,且反变换最小的非优秀$k-1$数对为$(y,x+2y)$,只要证明$x+3y>F_{k+2}$即可,设经过$i$次相加得到(易知$p+i=k-2$)。若$i=0$,那么$x+3y=3F_{p+2}+F_{p}\geq F_{p+4}+F_{p}>F_{k+2}$。若$i=1$,$x+3y=F_{p+2}+3(F_{p}+F_{p+2}) \geq 5F_{p+2} > F_{p+5}=F_{k+2}$。若$i>1$,则$(x,y)=(F_{i-2}F_p+F_{i-1}F_{p+2},F_{i-1}F_p+F_iF_{p+2})$,那么$x+3y=(3F_{i-1}+F_{i-2})F_p+(3F_i+F_{i-1})F_{p+2}$ $=(F_{i+1}+F_{i-1})F_p+(F_{i+2}+F_{i})F_{p+2}\geq F_{i+p}+F_{i+p-1}+F_{i+p+3}+F_{i+p+1}=F_{i+p+4}+F_{i+p-1}>F_{k+2}$。
综上所述,每个满足条件的数对,都可以通过一个优秀的$k-1$数对得到。
类似之前$x+2y\geq F_{k+1}$的证明,除了$(F_{k-1},F_{k})$,每个优秀的k-1数对只能反变换得到一个优秀的k数对,$(F_{k-1},F_{k})$也只能变出$2$个,那么归纳得到优秀的$k$数对恰好有$k+1$个。对于每次询问,通过所有的优秀的$k-1$数对就可以算出所有可行的答案。复杂度$O(Qlog\,X+log^2\,X)-O(log^2\,X)$
[agc018_c]
我贪心很gg啊。考虑先去掉一维,把问题变为n个数对,x个数选第一个,y个数选第二个,最大的和为多少。先按照第一维排序,很容易用贪心搞定前x+y个数的答案,然后后面每个数一定只能选第二个(因为选第一个一定可以用前面一个没用的替换),分成"去掉第二个最小的"和"换掉第二减第一最小并去掉第一个最小的"讨论一下即可。其实直接按照两维做差排个序,那么前一半只能放一,后一半只能放二,枚举断点即可。复杂度$O(nlog\,n)-O(n)$
[agc018_e]
我自己的题,直接写解题报告了...
[agc018_f]
[agc019_e]
ARC
[arc065_f]
先去掉所有被包含的区间,把原序列搞成一个$l$严格递增且$r$也严格递增的序列。$dp_{i,j}$表示搞完前$i$个操作,已经确定的位置(前$l_{i+1}\!-\!1$个中)有$j$个$1$的方案数,枚举新确定的一段中$1$的个数转移即可。复杂度$O(n^2)-O(n)$
[arc066_f]
这种不会做还调了2h,真是没救了。
容易发现预处理可以直接dp:$f_i=max{f_j+\frac{(i-j)(i-j+1)}{2}-S_i+S_j,f_i-1}$,拆开得到$f_j+\frac{j(j-1)}{2}+S_j+\frac{i(i+1)}{2}-S_i-ij$,维护一个凸壳一样的东西,再拿个单调栈扫一扫就可以优化到线性了。维护从前往后和从后往前的dp值$f$,$g$。对于每个询问,答案为:$MIN_{p\in (l,r)} \; f_l+g_r+\frac{(r-l)(r-l-1)}{2}-S_{r-1}+S_l$,考虑如何分治地计算,假设当前处理[l,r]内p的答案,那么对于$p\in (l,mid]$,把$(mid,r]$内的东西先加入单调栈,然后一样的扫一扫就可以得到$l\in [l,p), r\in (mid,r]$这一部分的答案,剩下就把区间分为$[l,p),(p,mid]$了。复杂度$O(nlog\,n)-O(n)$
[arc068_f]
容易发现一个非空deque从前后不停取可以得到$2^{si-1}$种序列 。那我们只用考虑1之前的情况。
由于1之前的序列一定可以用两个单调减序列搞出来,那么他的最长上升子序列不超过2。又因为第二个序列一定是第一个序列的补集,那么如果前面决策的时候空出了$i$,$i$就一定出现在第二个序列中,根据前面的结论,对于一个序列可以把小于第一个序列末的数字贪心地给第一个序列,如果要用第二个序列那就一定是剩下的数字依次出来。这样用$dp_{i,j}$表示决策了$i$个数字,最小的数字是$n\!-\!i\!-\!j\!+\!1$的方案数(同时$j$也代表之前未决策的数字),枚举和上个之间空出来的数字转移即可。复杂度$O(nk)-O(n)$
[arc070_f]
在交互题面前,我真的就是个白痴。
如果假人达到一半的话,那他们抱团就和真人一模一样了,那只有真人数严格大于假人数的时候有解。考虑如何用$n$次找出一个真人:由于询问在两个人时出现否定,那么他们中至少有一个假人,就把他们全部废掉,最后必定剩下一个真人。维护一个栈$s$:满足$s_{i-1}$说$s_i$是真人($s_1$为底部),那么这个栈中一定没有真人在假人前面,又由于这个栈中必有一个真人,那最后一个就是真人;每次插入$i$的时候就判一下他能不能当栈顶,不能连栈顶一起删掉即可。
[arc072_f]
非常好的数形结合,考虑把二元组变成$(v,vt)$,这样每次合并直接进行加法即可。那么加入一个东西,相当于把之前的坐标向右上方平移,再去掉x轴超过$L$的部分。进行删除就相当于把所有集合上的点与原点连线以下部分的半平面交,也就是所有关键点的凸壳。用一个deque维护关键点间的矢量即可。复杂度$O(n)-O(n)$
胡策
[Dagon]
如果最后有一个空区间,那么答案为最大的k-1个区间相加,下面计算没有空区间的情况。考虑把问题转化为,给定n个区间,要求自己再任选k个区间,并给原来的n个区间找一个新区间是其子区间:满足k个区间都被找了一次,并且k个区间的长度和最大。其合法首先要满足每个原区间都有一个子区间。考虑把原区间中有一个子原区间的区间全部去掉,那么问题就变为求把去掉后的区间分为x段(对每个1~k都要求一遍),再加上去掉的k-x个最大的区间,可以发现无论x取多少,答案要么小于有一个空区间的,要么一定合法。由于最后第一部分的结果形为$r_1-l_{a_1}+r_{a_1+1}-l_{a_2}+...+l_{a_m+1}-r_n$,那么贪心的选取a序列即可。总复杂度$O(n\log n)-O(n)$
[Div]
[Swap]
[简单树题]
考虑两个点的lca的深度的计算方式,将其中一个点到根路径上面所有边次数加一,另一个点到根路径上面边的权值乘次数之和即为lca深度。那么把所有的点按原来的编号分为$B$块,每块维护树链剖分上权值乘次数的和,以及整个块的深度和。再维护每个点深度即可。修改的时候,算出每个块中的次数,在二维树状数组上单点修改;询问根据数剖算出整块的答案,并把块外的利用lca算出即可。$B$取$\sqrt{\frac{n}{\log n}}$,总复杂度$O((n+Q)\sqrt{n\log n}\log n)-O(n\sqrt{n})$
也可以用动态点分治,对于每层单独处理出一个dfs序,再对于每层维护一个kdtree,第一维为原编号,第二维为dfs序编号,这样修改就是第二维一个区间内的所有数,询问就是第一维一个区间,第二维去掉子树所在区间。复杂度$O(n\log ^2 n+Q\sqrt{n})-O(n\log n)$。不过自己写搓了过不了啊。
[海蜇?海蜇!]
挺牛逼的子集变换。下文只考虑d=4的情况。考虑已知起点和终点怎么计算答案:设第$i$维的差为$d_i$,其中有$c_j$个$d_i$对于$j$。可以用$dp_{i,j,k}$表示用了远点到为$i$维为$j$的点,走了$k$步的方案数。第$k$步到达的方案数就是$\prod\limits_{\sum k_j = k} dp_{c_j,j,k_j}\cdot \frac{k!}{\prod k_j!}$,显然这是一个卷积的形式,那么先ntt出$dp_{i,j}$的点值表达(要处理$4k$个),然后就可以得到$k$步到达的点值表达,由于所有问题和的点值表达等于所有问题点值表达的和,插值可以最后进行。最后得到总共的用i步走到的方案数后,利用容斥减去之间第j步到达过此点的方案数即可。假设已经知道了所有$c_j$对应的个数,枚举$c_j$的值,每次的只要$O(k)$即可求和,所以这一步的总复杂度为$O(20dk^2+20^{d-1}k)-O(20dk)$。
考虑如何所处所有$c_j$已知情况下对应的个数,可以直接暴力$f_{i,j,a,b,c}$表示决策前$i$位,状态为$j$,绝对值差$1$有$a$个,$2$有$b$个,$3$有$c$个的方案数(这样需要展开转移卡卡常)。正解的做法是对每一位做乘法,假设知道了第i位,分离出$a_0,a_1,a_2,a_3,b_0,b_1,b_2,b_3$8个数组,那么$(a_0+a_1+a_2+a_3)\times(b_0+b_1+b_2+b_3)$和$(a_0-a_1+a_2-a_3)\times(b_0-b_1+b_2-b_3)$可以区分出奇偶,利用$(a_0+a_3)\times(b_0+b_3)$和$(a_0-a_3)\times(b_0-b_3)$即可算出$3$的答案和$a_0b_0+a_3b_3$,同理也可以算出$a_1b_1+a_1b_1$。这样每层递归要转移$6$次,总复杂度是$O(n^{\log_4 6})-O(n)$
[Paint]
大力枚举每一段用的数字,搞出每一段的取值区间,然后用个数组排下重。最后再利用组合数算一下,由于是区间的最多只有两个,组合数部分可以直接推推公式。复杂度$O(能过)$
[Comb Avoiding Trees]
[简单数据结构题]
考虑把每个点周围的分成孩子和父亲,这样每次修改就是修改一个区间和一个点,而且区间与区间之间是独立的。假设知道了一个数列,给每个数字加上1,那么对于整个数列异或和第i位有影响是当且仅当加完的数列中有奇数个数字是$2^i$的倍数。对于每个点,维护:当前一圈的异或值,当前修改一整个儿子区间次数,被单点修改的次数,对每个i他的儿子被单点修改的次数模$2^i$为j的次数的奇偶性。这样就可以迅速维护每个点和每个点周围的值了。由于j的求和为n,所以总复杂度为$O(n\log n)-O(n\log n)$