好题总结

Merging UOJ总结 and 好题总结

#22. 【UR #1】外星人

一开始随便搞出第一问答案,很显然的性质对$x$有变化的$a$一定是递减的,就拿一个桶直接记录可以达到的值

然后我开始想第二问,一开始想直接在这个桶上统计答案,然后发现不行,之后再想,如果利用上面的性质,在选取了一个$a_i \leq x$时,会有一段区间的$a$可以随便插入到$a_i$之后,然后就被一些组合数学的细节绕晕,没有想清楚,这一段区间是$(x \mod a_i,x]$,并且要在$a_i$中挑一个出来放在最前面,然后会发现$x \mod a_i$是一个子问题,搞出来这个合法方案排列数后,将$(x \mod a_i,x]$中的数,插入排列中,方案数$(sum[x \mod a_i]+1)(sum[x \mod a_i]+2)...(sum[x]-1)$,即$\frac{sum[x-1]!}{sum[x \mod a_i]!}$

那么就设$dp[i]$为当前$x=i$时最大答案,$f[i]$为$x=i$且满足最大答案时的方案数

$dp[i]=\max dp[i \mod a_j]$  $(a_j \leq i)$

然后f[i]由那些可以得到最大答案的$f[i \mod a_j]$根据上面的更新得到

代码

#33. 【UR #2】树上GCD

首先考虑枚举$LCA$,那么就是统计统计利用不同子树各个深度的信息来统计答案,由于是深度信息,那么考虑利用长链剖分来维护这个信息,首先常规套路是继承重儿子信息,暴力维护轻儿子信息

先假设有两个数组$a,b$其中$a[i],b[i]$分别表示以该选定的$LCA$为根时,某一棵子树内深度为$i$的点的个数

考虑枚举答案$k$,那么开始推式子

$\sum_{i=1}^{n} \sum_{j=1}^{m} [gcd(i,j)=k]a[i]*b[j]$

$\sum_{i=1}^{\lfloor \frac{n}{k} \rfloor} \sum_{j=1}^{\lfloor \frac{m}{k} \rfloor} [gcd(i,j)=1]a[ik]b[jk]$

$\sum_{i=1}^{\lfloor \frac{n}{k} \rfloor} \sum_{j=1}^{\lfloor \frac{m}{k} \rfloor} a[ik]b[jk] \sum_{d|gcd(i,j)} \mu (d)$

$\sum_{d=1}^{\lfloor \frac{n}{k} \rfloor} \mu(d) \sum_{i=1}^{\lfloor \frac{n}{kd} \rfloor} \sum_{j=1}^{\lfloor \frac{m}{kd} \rfloor} a[ikd]b[jkd]$

$\sum_{d=1}^{\lfloor \frac{n}{k} \rfloor} \mu(d) (\sum_{i=1}^{\lfloor \frac{n}{kd} \rfloor} a[ikd]) (\sum_{j=1}^{\lfloor \frac{m}{kd} \rfloor} b[jkd])$

在维护答案的时候,会产生对于一个数组下标为kd倍数的个数和,并且可以发现$a,b$数组可以简单的维护,只是每次重儿子继承上来的信息不能每一次都遍历一遍(轻儿子可以)

那么考虑根号分治

对于$> \sqrt n$的询问直接暴力查询,每一次查询是$\sqrt n$的时间复杂度,最终均摊时间复杂度为$O(n\sqrt n)$

对于$< \sqrt n$的询问,这样进行考虑,由于每一次dfs下去之后,进行重儿子继承的是一段重链不断向上更新,那么考虑记$dp[i][j]$表示当前重链继承上来深度$%i=j$的个数有多少,每次询问时$O(1)$,轻儿子合并时,更新$dp$值就可以了,然后如果更新到重链顶时,就清空$dp$数组(注意不能直接把所有的dp值都清空,只能清空用过的$dp$值,否则时间复杂度不对)那么均摊复杂度也为$O(n\sqrt n)$

代码

#32. 【UR #2】跳蚤公路

首先题目的意思就是让我们找出负环,解出$x$在环上不等式的解集

然后可以发现一个环的解集一定是一个形如$kx+b \geq 0$的形式,那么对于某一个点,其解集一定是一个连续的区间$[L,R]$,这样可以二分出来,注意这里先需要找出合法区间内的一个合法解,之后再能两次二分出左右端点,求一个合法解的方法也是二分,二分出$mid$后,如果不存在负环,那么说明这一定是一个合法解直接返回即可,如果有负环,那么用spfa跑出来之后,看是$+1$还是$-1$的边使得当前的图存在负环,只要记录一下到每一个点的$+1/-1$之和,如果为正,那么需要变大,如果为负,那么需要变小

那么最暴力的方法对于每一个点直接二分出这个区间,这样复杂度为$O(n^2mlogw)$

考虑强连通分量缩点,那么负环只有可能存在于强连通分量中,缩点后的图是一个DAG,最终某一个点的答案一定是1号点到这个点在DAG上走过所有强连通分量解集的交

那么有效的环一定是在某一个强连通分量中,只要对每一个强连通分量二分求出其合法区间即可,那么这个算法的上界是$O(nmlogw)$

那么最后合并答案的时候,只要进行拓扑序,然后上界取$min$,下界取$max$即可

题解中给出另外一种做法

考虑在spfa结束后,什么样的节点是在负环上的

设$f(n,i)$表示经过$n$轮之后到达$i$的最小路径

对于节点$i$,$i$在负环上的充要条件是

$f(n,i) \leq f(n-1,i)$

现在设$g(n,i,k)$表示经过$n$轮之和到达$i$并且到到这个节点的不等式$x$前的前的系数为$k$最短路径

$f(n,i)=\min\{g(n,i,k)+kx\}$

带入到上式得$ \min\{g(n,i,k)+kx\} \leq \min\{g(n-1,i,j)+jx\}$

解这个不等式即可

代码我只写了我的那个做法

代码

#310. 【UNR #2】黎明前的巧克力

感觉挺妙的,窝还是太菜

基本上可以一眼看出来这是XOR卷积的形式,每一个数可以放入两个集合中的一个或者不放,只要两个集合中的所有数异或起来等于$0$,那么这个方案就是合法的,但是由于集合不能相交,那就不能简单地把所有数放到对应位置上,然后直接自乘

那么需要一个个数的拆开分别卷起来,那么对于某一个数$a_i$,其对应的多项式$f(x)[a_i]=2,f(x)[0]=1$,需要把$n$个这样的多项式XOR卷积起来,得到的最终多项式才是最终答案

考虑在对一个多项式做FWT的时候得到的FWT每一位具体是什么

$FWT(A)[i]=\sum_{cnt(i\&j)=0} A_j-\sum_{cnt(i\&j)=1} A_j$

$0$位的对于每一位的贡献都是$+1$,而$a_i$对每一位的贡献要么是$+2$要么是$-2$,所以最终FWT出来的每一位要么是$3$要么是$-1$

那么如果计算出在所有多项式中每一位出现过多少个$3$,出现过多少个$-1$,就可以通过计算快速幂得到最终多项式

由于FWT是线性变换,那么$FWT(A+B)=FWT(A)+FWT(B)$,那么考虑将所有多项式相加压缩得到一个多项式,做一遍FWT,那么得到某一位上的值就是所有多项式FWT之后结果这一位值之和

设这一位上有$x$个$3$,$y$个$-1$

那么$3x-y=FWT[i],x+y=n$

解得$x=\frac{n+FWT[i]}{4},y=n-\frac{n+FWT[i]}{4}$

那么直接快速幂,IFWT回去即可

代码

#61. 【UR #5】怎样更有力气

首先可以想到可以将所有的加边操作按$w$排序,然后依次加入边

考虑如果$p=0$的时候,相当于现在没有任何限制,那么把所有$u$到$v$路径上所有点连成一个联通块,具体实现可以用一个并查集,维护,在把所有路径上节点找出来的时候,每一次跳的时候找到并查集中的根,然后跳过去,最后把这个路径缩成一个点

但如果有限制这样做是不行的

可以发现如果每一个操作的限制个数小于$u$到$v$的路径长度,那么一定可以把这个路径连成一个联通块,套用上面的做法即可

但如果限制个数大于等于路径长度,那么就有可能不能把整个路径连成一个联通块,那么现在的目标就是尽可能地去合并点

首先如果两个点没有限制,那么可以合并整个两个点,但之前枚举$w^2$($w$为这个路径上的点数),复杂度是错的

那么考虑去找到一个中继节点$rt$,使得尽可能多的点不跟其有限制,可以发现这个节点连出的限制最多只有$\sqrt(w)$个

设$S$为$rt$限制到的集合,$T$为$rt$没有限制到的集合

如果对于$x\in S$,$\exists y\in T$,$x$没有到$y$的限制,那么可以把$x$合并到$rt$上

然后暴力枚举两个$S$中的元素,判断能否合并,这一部分复杂度$O(w)$

总复杂度$O((p+n)logn)$

还有注意上面两钟情况,要分别维护两个并查集

代码

 

#50. 【UR #3】链式反应

题目可以转化为求$n$个节点可以产生二叉树,并且树上每一个节点可以外挂节点(也就是题目中的破坏死光照射到的节点)的数量,并且这个二叉树标号需要满足堆的性质

那么可以简单的设$dp[i]$表示用$i$个节点产生的二叉树的数量有多少个,其中$dp[0]=0$,$a[1...m]$表示可以外挂的节点数量(包含当前的根节点,也就是$01$串为$1$的下标$+1$)

那么$dp[n]=\frac{1}{2}\sum\limits_{i=1}^{m}\sum\limits_{j=0}^{n-a_i}\binom{n-1}{a_i-1}\binom{n-a_i}{j}dp[j]dp[n-a_i-j]$

直接做可以得到$40$分

考虑优化,继续推式子

$dp[n]=\frac{1}{2}\sum\limits_{i=1}^{m}\sum\limits_{j=0}^{n-a_i}\binom{n-1}{a_i-1,j,n-a_i-j}dp[j]dp[n-a_i-j]$

$\frac{dp[n]}{(n-1)!}=\frac{1}{2}\sum\limits_{i=1}^{m}\frac{1}{(a_i-1)!}\sum\limits_{j=0}^{n-a_i}\frac{dp[j]}{j!}\frac{dp[n-a_i-j]}{(n-a_i-j)!}$

推到这一步,如果把$a$看作一个在值域上的多项式$s$,那么这个就可以直接用分治$FFT$做了,分治的过程中维护一下$dp$和自己的卷积,$dp$和$s$的卷积,就可以计算得到所有的$dp$值,时间复杂度$O(nlog^2n)$,要注意的是维护$dp$与自己的卷积的时候,需要注意计算左边对右边贡献,那些用之前计算的$dp$值来卷$[l,mid]$的时候,如果次数$<l$,那么之前的系数要设为$2$,因为在做卷积的时候,这两个数相乘是做$2$次的

然后再考虑生成函数,设$F(x)=\sum\limits_n \frac{dp[n]}{n!}$

那么$F'=\frac{1}{2}s(x)F^2+1$

直接解是解不出来的

那么套用解一阶微分方程的牛顿迭代做法就可以了,时间复杂度$O(nlogn)$,巨大常数,根本跑不过分治$FFT$

代码

CF605E Intergalaxy Trips

把样例模拟清楚这道题就会做了

先设$dp[i]$表示从第$i$号节点到第$n$号节点最小期望

由于是贪心的选择最小期望值走过去,那么可以想到像最短路一样转移过去,其实就是DP转移有后效性,用最短路优化一下

考虑如何转移,对于一个节点$i$,可以走向的节点是那些已经固定下来期望的节点,人在这个节点的时候会根据连边情况,来决定往哪边走

因为这些已经固定的点的期望是单调的(最短路的性质)

那么把式子写出来是这样的,假设期望递增

$dp[i]=1+(\prod\limits_j(1-p[i][a_j]))dp[i]+\sum\limits_{j} (p[i][a_j]\prod\limits_{k<j}(1-p[i][a_k]))dp[a_j]$

然后移项,把$dp[i]$解出来即可,每一次更新的时候选择未固定节点进行转移即可

转移过程中维护一下那个连乘即可

代码

 

CF838D Airplane Arrangements

很妙

首先可以看作人从选定的节点出发,然后不断往某一个方向走,直到走到空座位或者走出门,由于有门的限制,这就需要枚举前后缀的长度,我推了一下式子,至少需要$O(n^2)$并且如果要继续优化需要组合数下指标求部分和

那么不妨把前后门接起来,这样所有的座位就变成了一个环,把飞机外面的空间也看作一个空座位标号为$n+1$,那么一个方案合法,当且仅当$n+1$这个座位为空

由于环上所有的元素都是等价的,相当于是说某一个方案,通过旋转可以从到达不同的地方,那么只有每一个位置非空的概率相同,才不会导致矛盾

那么$n+1$号座位为空的概率为$\frac{n+1-m}{n+1}$

总方案数为$(2(n+1))^m$

答案为$\frac{n+1-m}{n+1}(2(n+1))^m$

代码

CF1392H ZS Shuffles Cards

首先需要注意到的是,总期望等于期望进行洗牌的次数乘以一轮中期望第一次抽到鬼牌的次数

严谨的证明如下(Benq写的)

$\begin{align*} E[\text{# of seconds until game ends}]&=\sum_{i=1}^{\infty}E[\text{contribution of }i\text{-th iteration}]\\ &=\sum_{i=1}^{\infty}P[\text{game did not end after }i-1\text{ iterations}]\cdot E[\text{length of }i\text{-th iteration}|\text{game did not end after }i-1\text{ iterations}]\\ &=\sum_{i=1}^{\infty}P[\text{game did not end after }i-1\text{ iterations}]\cdot E[\text{length of any iteration}]\\ &=\left(\sum_{i=1}^{\infty}P[\text{game did not end after }i-1\text{ iterations}]\right)\cdot E[\text{length of any iteration}]\\ &=E[\text{# of iterations}]\cdot E[\text{length of any iteration}]\\ \end{align*}$

主要的思路就是每一轮抽卡都是独立的,也就是说每一次抽卡的次数不会受当前已有卡的集合影响

那么现在要求的两个期望就可以分开求

考虑求出一轮中期望第一次抽到鬼牌的次数

这个期望等价于,在第一张鬼牌之前牌的数量,考虑除$m$张鬼牌之外,只有一张正常的牌,那么这张牌排在所有鬼牌之前的概率是$\frac{1}{m+1}$,由于贡献为$1$,那么期望也为$\frac{1}{m+1}$,那么根据期望线性可得答案为$\frac{n}{m+1}+1$

再考虑求出期望要进行多少次洗牌

设$dp[k]$表示当前还有$k$个没有在集合里的牌

由于不考虑具体抽了几次,那么就可以看作牌堆中只有$k$个还没有在集合中的卡还有$m$张鬼牌,那么考虑第一张牌,是没在集合中的卡的概率为$\frac{k}{m+k}$,那么就可以删掉这张牌,转化为$dp[k-1]$,鬼牌的概率为$\frac{m}{m+k}$,这一轮立刻结束,重新洗牌,转化为$dp[k]+1$

$dp[k]=\frac{k}{m+k}dp[k-1]+\frac{m}{m+k}(dp[k]+1)$

$dp[k]=dp[k-1]+\frac{m}{k}$

其中$dp[1]=m+1$因为只有一张牌,只要这张牌出现在第一个位置上,那么立刻结束,其概率为$\frac{1}{m+1}$

主要是第一步,这种迭代的问题,每一次洗牌之后都可以看作一个重新的开始

代码

[十二省联考2019]皮配

首先考虑$50$分做法,注意到由于阵营派系的和是固定的,那么如果只记录蓝阵营和鸭派系,就可以得到所有的信息,那么可以设$dp[i][j][k]$表示前$i$个城市中,蓝阵营的人数为$j$个,鸭派系的人数为$k$个

那么就可以直接转移,其中第一维是可以滚动掉的,还要注意在转移的时候,需要将这城市的两种选择分开进行转移,然后对于每一个学校再做$0/1$背包

最后将这两种转移得到的答案相加即可更新$dp$

再考虑$k=0$的时候,由于所有的选择都是对称的,那么就可以将原来的$dp$的两维分别拆开,记阵营的背包为$F$,派系的背包记作$G$,然后就可以单独进行转移,最后把答案对应相乘即可

最后是考虑正解,注意到$k\leq 30$,那么这就提示我们单独对于这$k$个特殊的学校进行转移,考虑那些没有特殊学校的城市,这些城市可以直接套用上面的$k=0$的做法,然后考虑有特殊学校的城市,城市中可能还有其他没有限制的学校,那么这些学校一旦阵营选定,选派系可以随便选(都是对称的,那么不管选哪个阵营,其方案数都是一样),那么我们先不考虑这整个城市选了哪个阵营,对于没有特殊限制的学校套用$k=0$的做法,但把其对阵营方面的人数看作$0$,将那些有特殊限制的学校在阵营方面的人数视为整个城市的总人数,对于这些特殊学校,就用50分的做法,得到对应的$dp$数组

把这些$dp$都处理好之后,那么剩下的就是如何合并这两个做法的背包

最$naive$的做法,就是暴力卷积,复杂度$O(m^4)$

但是写出式子,可以发现,如果考虑$dp[i][j]$对答案的贡献,与之乘起来的$F$和$G$都是一段连续的区间,那么预处理前缀和即可

还有需要注意一点,在做特殊学校的$dp$时,如果一直循环到$m$,会被卡$T$一个点,需要记录前缀和,循环到当前的前缀和

代码

「USACO 2020.12 Platinum」Spaceship

这道题搞了我一个晚上,歪果仁的DP还是很妙

这道题主要有两个想法,首先可以发现对于按钮序列上最大不合法位置一定是单调递增的,并且当按了最大那个之后,如果不去按更大的按钮,那么这个按钮之后就一定按不了,那么如果只考虑当前最大不合法的按钮为$x$的话,对于图上任意一个路径最多只有一个节点是按了第$x$个按钮

考虑设$dp[s][t][k]$表示从$s$出发到$t$,其中路上按下按钮的最大位置为$k$的方案数,由于这个路径上最多只有一个位置为$k$,那么考虑枚举这个位置$r$,那么$s$到$r$这一段路径和$r$到$t$这一段路径(其中这两条路径都不包括$r$)最大可以按下按钮的位置为$k-1$,那么方案数就为$(\sum\limits_a dp[s][a][k-1])(\sum\limits_b dp[b][t][k-1])$其中存在一条边$a$到$r$,$r$到$b$,这两个和式可以通过预处理得到,其中需要注意分成的左右两段可以为空,即在$i$处或$j$处按下$k$位置的按钮,需要单独处理一下

那么现在考虑处理询问,注意到询问是强制在$s$节点按下$b_s$位置的按钮,直接处理不好处理,考虑新加两个虚拟节点,表示起点和终点,那么套用上面的$dp$即可,其中$a,b$不能是特殊点,并且在处理特殊情况的时候,如果当前枚举到的$k$是符合条件的,那么才能把方案数加上去

对于多组询问,不需要每一次都重新就算一遍DP,加入$2q$个特殊点,转移的时候强制某一个询问的出发点只能对应相应的终点

但还有一种无脑做法,可以发现转移方程本质上就是在做矩阵乘法,可以预处理转移矩阵的若干次方

代码

[ICPC2015 WF]Tours

真诚膜拜hhz

首先需要注意到如果把所有环都拆成若干个不相交的边集,那么只要在这个边集中的边内均匀分布各种颜色,那么这些集合组合起来得到的环一定也是均匀分布的,那么最终答案就是所有集合大小的$gcd$的所有因子

考虑如何拆出这些集合,有两种做法

首先对于某一个边集,那么都在某一个环里,要么都不在,那么如果把这条边断掉,那么那些存在这个集合的环,都会被破坏掉,那么对于集合中其他的边,都不会存在于任何一个环中,那么这些边形成了桥,那么只要对于原图上每一个非桥边,将这条边断掉,图上增加了$x$个桥,那么这个集合大小就是$x+1$,时间复杂度$O(nm)$

还有一种$O(n)$做法,考虑将原图的一个生成树找出来,对于那些非树边和两个端点在树上形成的路径,就形成了一个环,那么对于这个环上的边,需要被单独划分成若干集合,那么可以对于每一条边记录被非树边覆盖的集合,对于集合相同的,那么这些边就在同一个集合中,对于如何统计被覆盖的集合,可以对每条非树边随机一个值,定义一条边的权值为所有覆盖它的非树边随机值的异或和,值域较大的话,冲突概率很小,直接树上差分即可

代码

[ZJOI2016]大森林

首先可以发现,对于某一位上的树,其形态是固定的(也就是说,对于某一个已经加入的点,其位置是不会改变的),那么只要询问的位置合法,那么询问的答案一定不会变,那么不妨将所有的询问放到最后

然后又注意到询问只会询问那些存在于树上的点对,那么将$0$操作改为对于全体的树都进行生长是不会影响答案,但是需要保证$1$操作不对没有$x$节点的树进行修改

那么现在难以处理的就只剩$1$操作,对于某一个$1$操作,可以发现的是,对于所有在这个$1$操作之后生长的点之间的相对关系是不受这个操作影响的,那么这个$1$操作影响的只有之后生长节点的父亲,那么相当就是把这些节点的父亲改到$x$处,那么对于修改区间的影响,只要在端点处记录,左端点将子树改到$x$,右端点撤销

这个可以用$LCT$维护,但是不能直接一个一个这些节点$cut$,那么可以对于每一个$1$操作建虚点,对于某一段$0$操作加入的点,将这些点连向最近一次$1$操作对应的虚点,注意这里如果新加一个$1$操作,那么这个$1$操作的虚点也需要连向上一个$1$操作的虚点,这样才能保证对于一次修改操作,只需要$link,cut$一个点

剩下的就只剩如何求出两个点之间的距离,由于在维护的过程中强制使$LCT$有根,那么不能进行$makeroot$操作,那么需要找到两个点的$LCA$,用其深度来计算距离,对于两个点$x,y$其$LCA$就是$access(x)$后进行$access(y)$时,最后跳得一条轻边的顶节点,求深度的话,就直接$access$求出这条链上有几个实点

代码

 

[CERC2017]Buffalo Barricades

首先需要考虑倒推,先计算出不考虑加入栅栏时间,每一个栅栏围住水牛的数量这可以用从上向下扫描线,并且用$set$维护一下

在扫描到水牛的时候,在$set$里二分出其左边第一个遇到的栅栏将这个栅栏的答案加1

如果遇到是一个新的栅栏,那么暴力向左边跳,直到遇到第一个时间比这个点早的栅栏,在过程中遇到的栅栏都删去

但是还要考虑如何计算由于时间差多出来的答案,可以发现如果某一个栅栏$x$时间比另外一个栅栏$y$时间早,并且$x$包含$y$,那么$y$的答案就要加到$x$的答案上

可以发现在维护扫描线的过程中,对于某一个栅栏,其最近包含它的另外一个栅栏就是在$set$中比这个栅栏大的那一个,那么其实包含关系形成了一个树形结构,某一个点的答案就是在这个点子树内最大包含这个点的联通块原来答案之和,这个联通块不含时间比这点早的节点

那么考虑按时间顺序从后往前统计答案,那么只要用并查集维护当前联通块的总和即可

代码

CF643F Bears and Juice

根本想不到,想到也想不清楚为什么,终于想出来为什么了

首先抛出一个式子$\sum\limits_{k=0}^p \binom{n}{k} q^k$表示用$q$天,可以确定酒桶最多桶数

需要这样考虑,首先考虑两桶饮料之间的关系,喝这两桶饮料熊的集合(如果哪一天喝的不同,算是不同集合)肯定不会相同,否则就区别不出这两桶饮料,并且一头熊不会喝同一桶饮料多次,这个是显然的

有了这个性质,那么可以断言最多桶数就是可以产生不同集合的数量

大概就是由于有酒的桶就只有一个,通过观察分配到这个桶集合的熊和去睡觉的时间,就可以确定是这个桶有酒,应为其他桶的集合不会因为喝了其他桶的果汁产生任何变化,那么只需要保证所有桶的集合不同即可

那么考虑枚举集合内有多少个熊和喝天数的分配,就可以得到上面的那个式子

代码

posted @ 2020-12-07 21:46  SevenDawns  阅读(142)  评论(2编辑  收藏  举报
浏览器标题切换
浏览器标题切换end