F. Fancy Arrays
快速幂 容斥

数列个数,看起来像快速幂,问题是没有最大值可能很大,直接快速幂的话矩阵太大。
考虑容斥转化成一个矩阵大小 O ( x ) O(x) O(x)的快速幂问题:至少有一个元素在 [ x , x + k − 1 ] [x,x+k-1] [x,x+k−1],等价于最小值小于 x + k x+k x+k,且最大值大于等于 x x x的数列个数,如果最大值就在 [ x , x + k − 1 ] [x,x+k-1] [x,x+k−1],显然满足条件,如果最大值大于等于 x + k x+k x+k,那么由于相邻项跨度不超过 k k k,从小于 x x x的最小值到大于等于 x + k x+k x+k的最大值中间,一定有一步会落在 [ x , x + k − 1 ] [x,x+k-1] [x,x+k−1],这类似于离散版的介值定理。
故我们要求的数列个数,就可以由容斥转化为:等价于最小值小于 x + k x+k x+k的个数,减去最大值小于 x x x的个数。
最小值小于 x + k x+k x+k的方案数,从每一步的跨度构成的数组来看,确定了这个数组就能确定数列的形状,每一步跨度都有 [ − k , k ] [-k,k] [−k,k]共 2 k + 1 2k+1 2k+1种选择,一共有 ( 2 k + 1 ) n (2k+1)^n (2k+1)n种形状,然后可以上下平移,对于每一个形状,让他的最小值小于 x + k x+k x+k,也就是在 [ 0 , x − k + 1 ] [0,x-k+1] [0,x−k+1],有 x + k x+k x+k种选择,总方案数 ( x + k ) ( 2 k + 1 ) n (x+k)(2k+1)^n (x+k)(2k+1)n
最大值大于等于 x x x,也就是所有元素值域都在 [ 0 , x − 1 ] [0,x-1] [0,x−1],且跨度不超过 d d d, x x x很小,直接矩阵快速幂 d p dp dp即可
E. Darth Vader and Tree
树上dp 矩阵快速幂

自相似的树,考虑一个点的儿子,儿子为根的子树,和父亲为根的子树是一样的,可以通过这一点来 d p dp dp转移,比如本题,统计到根距离 x x x的点,等价于到儿子距离为 x − d i x-d_i x−di的点,每个儿子都可进行这样的转移。
注意儿子虽多,但 d i < = 100 d_i<=100 di<=100,并不多,可以用桶统计各种 d i d_i di的儿子,一次一共只有 100 100 100个转移。并且不同的 x x x,转移都是一样的 f x = ∑ f x − i f_x=\sum f_{x-i} fx=∑fx−i,只有 100 100 100个转移,可以考虑矩阵快速幂优化。
C. Fountains
枚举 二分

买一个金币,一个钻石,分别求不超过对应货币数的最大价值即可。
买两个金币,可以枚举一个,然后可知剩余货币,求价值不超过剩余货币的最大价值,把金币按照价值升序,然后维护前缀最大价值,再二分即可。
两个钻石同理
E. Hidden Knowledge of the Ancients
滑窗 map维护元素种类

元素种类随区间边长有单调性,滑窗即可,注意还有区间长度的限制。
C. Monocarp's String
扫描线前缀和 dp

删去一个区间,剩余的ab相等,等价于选择一个区间 a − b a-b a−b的个数为特定值。数据结构维护 a − b a-b a−b个数的前缀和,枚举所有前缀,对于一个前缀,计算出,可以和他形成合法区间的另一个前缀,前缀和应该是多少,去数据结构查询这个前缀和值的最大长度,即可得到以当前前缀结尾,为右端点的最短合法区间
如果 s s s包含三种字母,类似地可以分别维护 a − b , b − c , c − a a-b,b-c,c-a a−b,b−c,c−a的个数,这三个值共同组成一个前缀的状态,把他们压缩成一个对象,作为 m a p map map的查询 k e y key key,剩下照旧。
该方法可以拓展到更大的字符集。
D. Flags
带前缀和的矩阵快速幂 状压 回文

不能出现黑白红,红白黑,状态里需要记录前两个元素的颜色。
需要求很长的序列的方案数,考虑矩阵快速幂优化,状压记录前两个颜色,并根据其它规则构造转移矩阵。
求的是区间和,可转化为前缀和,求的是长度 [ 1 , x ] [1,x] [1,x]之间的序列的方案数,这可以在 d p dp dp转移同时维护一个前缀和项,第 i i i轮的前缀和项,首先继承 i − 1 i-1 i−1轮的前缀和,并且所有 ( i − 1 , i ) (i-1,i) (i−1,i)的转移,都要复制一份转移到前缀和项,相当于前缀和加上了 i i i的方案数。
还要去除逆序,也就是回文串贡献一次,两个互为逆序的只贡献一次,答案是 ( 全部 − 回文 ) / 2 + 回文 (全部-回文)/2+回文 (全部−回文)/2+回文,所以还需要求回文个数。回文只需要枚举前一半,后一半根据回文特性已经确定了,也可以套用前面的矩阵快速幂优化 d p dp dp,长度除二即可
B. Pairs of Numbers
正序转倒序

状态是个数对,顺着到达目的地,不好做,考虑从目的状态出发倒着来,往往是正着会有很多分支,但倒着来路径是确定的。
比如这题正着每一步有两个分支,倒着等价于 ( a , b ) (a,b) (a,b)里较大的减去较小的,过程是完全确定的。接下来求步数,由于 a , b a,b a,b很大,不能完全模拟。观察模拟过程,实际上就是大的不断减去小的,知道大小关系变化,熟悉数论的可以发现这就是求 g c d gcd gcd辗转相减,只是 g c d gcd gcd关心最终 a , b a,b a,b的值,我们现在关心进行的操作次数,那么对其优化显然就是优化成辗转相除,每次较大的对较小的取模,即可直接跳过一段相同的减法操作,有解的话,最后应该是 ( a , b ) = ( 1 , x ) (a,b)=(1,x) (a,b)=(1,x)的形式,如果是 ( 0 , x ) (0,x) (0,x)则无解。
终点有多种选择,注意到 ( i , n ) ( n , i ) (i,n)(n,i) (i,n)(n,i)是对称的,只有枚举一边,并且 i > n i>n i>n的,第一轮会先转移到一个 ( i , n ) , i < n (i,n),i<n (i,n),i<n,所以我们只用枚举 i ∈ [ 1 , n ] i∈[1,n] i∈[1,n]就是最优的
D. Count GCD
gcd 容斥

gcd是个不断取质因子集合交集的过程,因此首先随着元素增加,gcd一定不断变小。其次增加一个元素之后,新的gcd一定是之前的一个因子。最后来考虑方案数,前一个gcd=y,当前gcd=x,那么这一次加入的元素,一定是 x x x的倍数,但不是 z = k x , x < z < = y z=kx,x<z<=y z=kx,x<z<=y的任何一个 z z z的倍数,否则gcd会是z而不是x。
在值域内,总的 x x x倍数有 m / x m/x m/x,我们要减去所有至少是一个 z = k x , x < z < = y z=kx,x<z<=y z=kx,x<z<=y的倍数的数字的个数,就是合法的元素个数。注意到至少是集合中一个数的倍数,这可以容斥计算。
C. Strong Password
子序列自动机

如果是子序列,也就是能匹配上,我们如何验证?就是经典的子序列自动机,我们把模式串作为自动机,s作为输入的语言,枚举s,根据当前在t上的指针位置,决定t形成的自动机能否转移,如果能转移到结尾就能匹配上。
现在问能否不匹配上,仍然考虑把t作为自动机,s作为输入串,匹配不上就是扫完s,没转移到t的终态,我们能构造t,那贪心的想,就要通过构造,让t的转移尽量慢,也就是,直到s里 [ l i , r i ] [l_i,r_i] [li,ri]的字符都出现过了,我们才认为 t t t的 i i i位置匹配上了,这样匹配时最慢的,如果这样最后仍然匹配上了,则怎么构造 t t t,都不存在 t t t不是 s s s的子序列。
F. Points
线段树维护滑窗

考虑静态。可以枚举 z z z,然后对于每个 z z z,在 [ z − d , z − 1 ] [z-d,z-1] [z−d,z−1]里选两个不同元素作为 x , y x,y x,y,假设 [ z − 1 , z − d ] [z-1,z-d] [z−1,z−d]元素个数为 k k k,那么贡献就是 C ( k , 2 ) = k ( k − 1 ) / 2 = ( k 2 − k ) / 2 C(k,2)=k(k-1)/2=(k^2-k)/2 C(k,2)=k(k−1)/2=(k2−k)/2
动态增减元素的话,考虑对值域建线段树,每个位置 i i i维护 [ i − d , i − 1 ] [i-d,i-1] [i−d,i−1]的 k , k 2 k,k^2 k,k2,用一个区间求和线段树,得到所有位置的 k 2 , k k^2,k k2,k和,即可求出答案。
这其实是一种不太常见,但也有套路的线段树设计,也就是线段树上 i i i点,不对应序列/值域的 i i i点,而是对应以 i i i开头/结尾的一段区间,这常见于原问题静态时,答案的求法时跑一个定长滑窗,确定了滑窗的端点即可统计答案,那么我们让线段树维护这些滑窗内的情况,即可解决动态问题。
考虑更新,加入一个数 i i i,会影响 [ i , i + d ] [i,i+d] [i,i+d]为右端点的滑窗的 k , k 2 k,k^2 k,k2,也就是一个区间更新,需要懒标记,懒标记的核心就是 p u s h d o w n pushdown pushdown和更新时递归到一个最小区间的更新,两部分逻辑类似,一块考虑。
也就是我们对一个区间的 k k k都 + f +f +f,这个区间的 k , k 2 k,k^2 k,k2标记分别会如何变化? k k k的变化就是每一个位置 i i i,都 + f +f +f,但前提是 i i i位置有元素,所以整个区间的 k k k变化是, + = c n t ∗ f +=cnt*f +=cnt∗f, c n t cnt cnt是区间内有元素的位置个数,因此区间标记需要增加一个 c n t cnt cnt,这很好维护,单点修区间和即。 k 2 k^2 k2的变化,写出增量表达式 ( k + f ) ( k + f ) − k 2 = ∑ ( 2 k f + f 2 ) (k+f)(k+f)-k^2=\sum (2kf+f^2) (k+f)(k+f)−k2=∑(2kf+f2),这里的求和也是对所有位置 i i i来说,前提是 i i i位置有元素。故等于 2 f ∑ k + c n t f 2 2f\sum k+cntf^2 2f∑k+cntf2,用 k , c n t k,cnt k,cnt标记即可更新。
加入一个数,最后递归到 i i i的叶子,更新这一点的 c n t = k = k 2 = 1 cnt=k=k^2=1 cnt=k=k2=1
删除一个数,对 k , k 2 k,k^2 k,k2的区间更新和上面类似,可以复用函数, f = − 1 f=-1 f=−1即可。单点修该则是 i i i位置 c n t = k = k 2 = 0 cnt=k=k^2=0 cnt=k=k2=0