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

DP优化

这里主要引入蒙日矩阵的优化,wqs二分,slope trick等技巧。

蒙日矩阵

首先引入一些定义相关。

我们有 f [ i ] = m i n j ( g [ j ] + A [ i ] [ j ] ) f[i]=min_j(g[j]+A[i][j]) f[i]=minj(g[j]+A[i][j])。形式化的,就是f=A*g。

我们称一个矩阵为单调矩阵的话,那么就对于每一行,最小值的位置b[i],有随着i的增加b[i]单调不降。如果有多个最小值,那么可以以每行最左或最右为定义,每行定义相同即可(虽然好像不同定义引出不同结果,但是大概(猜的)满足一种定义有为单调矩阵的结果,那么这个就有单调矩阵相关性质)。

我们称对于任意一个子矩阵(未必连续)都为单调矩阵的矩阵为完全单调矩阵。

我们定义满足 ∀ x ≤ u , y ≤ v , a x , y + a u , v ≤ a x , v + a u , y \forall x\leq u,y\leq v,a_{x,y}+a_{u,v}\leq a_{x,v}+a_{u,y} xu,yv,ax,y+au,vax,v+au,y的矩阵满足四边形不等式,我们声称(我不会证)满足四边形不等式的矩阵是完全单调矩阵。我们又声称 ∀ x , y , a x , y + a x + 1 , y + 1 ≤ a x , y + 1 + a x + 1 , y \forall x,y,a_{x,y}+a_{x+1,y+1}\leq a_{x,y+1}+a_{x+1,y} x,y,ax,y+ax+1,y+1ax,y+1+ax+1,y是原命题的充分必要条件。作为原命题的一个子命题,必要性显然。然后考虑对于横着相邻的两个这样的式子不断加一加,就可以得到所有长宽为2*n的四边形不等式,再把这些竖着和自己加一加,就可以得到所有的四边形不等式,所以这个是充分的。

我们称一个满足了四边形不等式的矩阵为蒙日矩阵,蒙日矩阵必然是完全单调矩阵,但完全单调矩阵未必是蒙日矩阵。我们接下来探讨的都与蒙日矩阵有关。

给出性质,对于一个单调矩阵,整行加和整列加之后仍然是单调矩阵。

对于一个单调矩阵A,我们可以有一些手段来优化 f [ i ] = m i n j ( g [ j ] + A [ i ] [ j ] ) f[i]=min_j(g[j]+A[i][j]) f[i]=minj(g[j]+A[i][j])的求取方式。

方法为分治,由于这个相当于A矩阵的整列加之后求取每行最小值,所以考虑求出f[mid]的决策点,然后我们知道<mid部分决策点小于f[mid]的决策点,>mid的类似,然后就可以分治下去了。只能用于离线问题。

对于一个单调矩阵A,我们可以有一些手段来优化 f [ i ] = m i n 0 ≤ j < i ( f [ j ] + A [ i ] [ j ] ) f[i]=min_{0\leq j< i}(f[j]+A[i][j]) f[i]=min0j<i(f[j]+A[i][j])的求取方式。

方法为二分栈,由于这个相当于一个在线整列加的一个求取每行最小值,考虑到对于第i列,我们可以发现在i+1-n的掌控区域未考虑时,是一个行标号后缀,所以考虑用一个二分栈维护。在加入一个新列时,我们先考虑栈顶是否绝对不优,是的话就弹掉,否则在这个栈顶掌握的区间上二分,得到新列更优所对应的后缀。这个方法也可以解决上一个问题,可以用于离线和在线。

接下来介绍一下蒙日矩阵乘法,首先 C [ i ] [ j ] = m i n k ( a [ i ] [ k ] + b [ k ] [ j ] ) C[i][j]=min_k(a[i][k]+b[k][j]) C[i][j]=mink(a[i][k]+b[k][j]),我们记对于i和j,转移点为 s [ i ] [ j ] s[i][j] s[i][j],有结论 s [ i ] [ j − 1 ] ≤ s [ i ] [ j ] ≤ s [ i + 1 ] [ j ] s[i][j-1]\leq s[i][j]\leq s[i+1][j] s[i][j1]s[i][j]s[i+1][j],所以可以从左下角开始沿着一个个对角线考虑到右上角。由于对于每一个对角线,暴力去做的话每个点对应的可决策区间之间重叠部分长度O(1),所以对于一整个对角线,暴力转移复杂度O(n),所以总共复杂度 O ( n 2 ) O(n^2) O(n2)。蒙日矩阵的积仍为蒙日矩阵。

例题

lg1912 诗人小G

我们考虑转移为 f [ i ] = m i n 0 ≤ j < i ( f [ j ] + ( s [ i ] − s [ j ] + i − j − 1 ) P ) f[i]=min_{0\leq j<i}(f[j]+(s[i]-s[j]+i-j-1)^P) f[i]=min0j<i(f[j]+(s[i]s[j]+ij1)P)。也即 A [ i ] [ j ] = ( s [ i ] − s [ j ] + i − j − 1 ) P A[i][j]=(s[i]-s[j]+i-j-1)^P A[i][j]=(s[i]s[j]+ij1)P

考虑运用四边形不等式,
A [ x ] [ y ] + A [ x + 1 ] [ y + 1 ] − A [ x + 1 ] [ y ] − A [ x ] [ y + 1 ] = ( ( s [ y ] − s [ x ] + y − x − 1 ) − ( s [ y ] − s [ x + 1 ] + y − x − 1 − 1 ) ) ( ⋯   ) + ( ( s [ y + 1 ] − s [ x + 1 ] + y − x − 1 ) − ( s [ y + 1 ] − s [ x ] + y − x + 1 − 1 ) ) ( ⋯   ) ( 使用 a p − b p = ( a − b ) ( ⋯   ) 公式 ) = ( s [ x + 1 ] − s [ x ] + 1 ) ( ⋯ − ⋯   ) A[x][y]+A[x+1][y+1]-A[x+1][y]-A[x][y+1]\\ =((s[y]-s[x]+y-x-1)-(s[y]-s[x+1]+y-x-1-1))(\cdots)\\ +((s[y+1]-s[x+1]+y-x-1)-(s[y+1]-s[x]+y-x+1-1))(\cdots)\\ (使用a^p-b^p=(a-b)(\cdots)公式)\\ =(s[x+1]-s[x]+1)(\cdots-\cdots) A[x][y]+A[x+1][y+1]A[x+1][y]A[x][y+1]=((s[y]s[x]+yx1)(s[y]s[x+1]+yx11))()+((s[y+1]s[x+1]+yx1)(s[y+1]s[x]+yx+11))()(使用apbp=(ab)()公式)=(s[x+1]s[x]+1)()
我们考虑两个省略号具体部分,可以发现上一项是两个值分别<=下一项两个值,那么公式中对应的高次相乘相加的一堆东西不难发现上一项<=下一项,所以上述值<=0,也就满足了四边形不等式。之后运用二分栈即可。

之后对于四边形不等式的证明将略去,因为证明比较困难,在实际考试中如果证不出来,可以写个程序暴力拍几组试试是否满足四边形不等式。

loj6039 珠宝

我们考虑把c相同的放到一起,可以知道如果从中选,必然是选前k大。所以有转移 f i , j = m a x ( f i − 1 , j − k ∗ i + s [ i ] [ k ] ) f_{i,j}=max(f_{i-1,j-k*i}+s[i][k]) fi,j=max(fi1,jki+s[i][k]),可以在模i意义下划分等价类,然后在每个等价类中有转移 f i = m a x ( f j + s [ p ] [ i − j ] ) f_i=max(f_j+s[p][i-j]) fi=max(fj+s[p][ij]),然后由于s[p]是上凸,所以这个显然满足四边形不等式,就可以直接做了。考虑对于每一层 ∑ s z 每个等价类 = m \sum sz_{每个等价类}=m sz每个等价类=m,所以时间复杂度为 O ( c m l o g m ) O(cmlogm) O(cmlogm)

uoj672 航天飞机调度

先考虑挖掘凸多边形的三角划分的性质,这里我们这里数字按顺序在凸多边形外绕一圈。对于 ∀ x ≤ u ≤ y ≤ v \forall x\leq u\leq y\leq v xuyv,有 d i s ( x , y ) + d i s ( u , v ) = d i s ( x , w ) + d i s ( y , w ) + d i s ( u , w ) + d i s ( v , w ) ≥ d i s ( x , v ) + d i s ( u , y ) dis(x,y)+dis(u,v)=dis(x,w)+dis(y,w)+dis(u,w)+dis(v,w)\geq dis(x,v)+dis(u,y) dis(x,y)+dis(u,v)=dis(x,w)+dis(y,w)+dis(u,w)+dis(v,w)dis(x,v)+dis(u,y)

考虑P递增的情况中,我们有了这一个性质,就可以有一个结论,就是如果有一个飞机同时用了两次,那么之后都是这一架,也即是先交替飞行再一直飞一架,我们可以询问出 P i P_i Pi P i − 1 P_{i-1} Pi1 P i − 2 P_{i-2} Pi2距离总共2q次询问之后一顿乱搞(比如前缀和优化或DP之类)就好了。考虑证明结论,用反证法,如果结论错误,那么存在严格最优情况有 P x P_x Px飞向 P y P_y Py P i P_i Pi飞向 P i − 1 P_{i-1} Pi1,且 x < i < i + 1 < y x<i<i+1<y x<i<i+1<y,那么我们可以发现由上面那个结论就有 d i s ( x , y ) + d i s ( i , i + 1 ) ≤ d i s ( x , i + 1 ) + d i s ( i , y ) dis(x,y)+dis(i,i+1)\leq dis(x,i+1)+dis(i,y) dis(x,y)+dis(i,i+1)dis(x,i+1)+dis(i,y),所以矛盾,原命题成立。

我们考虑一般情况,可以发现这个非常像四边形不等式,但是四边形不等式中没有行与列的大小限制。所以考虑将左下角直角边长n-1的一个直角三角挪到最右侧,剩下填上-INF,构成一个 n ∗ ( 2 ∗ n − 1 ) n*(2*n-1) n(2n1)的新矩形,可以发现就满足了四边形不等式(发现不等号反了,所以这个是max的四边形不等式)。考虑一般DP,有 f i + 1 , j = m i n ( f i + 1 , j , f i , j + d i s ( P i , P i + 1 ) f_{i+1,j}=min(f_{i+1,j},f_{i,j}+dis(P_i,P_{i+1}) fi+1,j=min(fi+1,j,fi,j+dis(Pi,Pi+1) f i + 1 , i = m i n ( f i + 1 , i , f i , j + d i s ( P j , P i + 1 ) ) f_{i+1,i}=min(f_{i+1,i},f_{i,j}+dis(P_j,P_{i+1})) fi+1,i=min(fi+1,i,fi,j+dis(Pj,Pi+1)),我们发现可以先改前者为赋值,再进行后者的取min。前者相当于一个全局加,询问一次就行了。后者相当于一个一行min的询问,可以想到决策单调性,我们可以获得决策点,然后就询问一次转移了。考虑如何获得决策点,初始时随便处理,操作时,发现我们每轮的全局加不影响决策,在单点取min时若改变了值,那么知道只会变小,所以它作为一个列控制的行只会变多,考虑一个二分,向两侧二分出新控制的范围(就是二分出比原控制者更优的区间左右端点),然后更新就可以了。二分时为了获得单点当下被谁控制,与之后的区间覆盖,所以要用一个线段树,复杂度 O ( q l o g 2 n ) O(qlog^2n) O(qlog2n),询问次数 O ( q l o g n ) O(qlogn) O(qlogn)

lg8864 序列变换

考虑先一个简单trick,将其前缀和化处理掉。然后考虑操作就等价于交换两个点的值,下文s指a的前缀和数组,都是基于s序列展开讨论。考虑当s[l-1]=0时,如果k为偶,那么要求就相当于有最多k/2段的连续1,如果k为奇,那么要求就相当于最多k/2的连续1,同时可以多一段连续1,但是必须这段包含r。可以考虑暴力求出 f [ l ] [ r ] f[l][r] f[l][r]表示把l-r的1聚在一起的最小步数,暴力求出 g [ l ] [ r ] g[l][r] g[l][r]表示把l-r的1聚在一起同时位于最右的最小步数。那么考虑求出一个 f k / 2 f^{k/2} fk/2 f k / 2 ∗ g f^{k/2}*g fk/2g,就回答了原问题,可以理解为EGF的 e f e^f ef那种类似的操作。而f和g都是蒙日矩阵,所以可以用相关优化。

wqs二分

假设现在有若干个量,每个有一个限制(恰好),然后求最大价值,所以大概朴素DP是 O ( n k ) O(n^k) O(nk),考虑随着一维a限制的变大,价值曲线形成了一个凸包。那么我们可以用一条线去割这个凸包,尝试求截距最大值,也就是在用a时必须多一个代价-k,然后去求最大价值就得到了与这个凸包相切的线,考虑我们在DP转移时多记一个最大时a的用量就可以同时得到此时f(x)和x,而且DP少一维,时间复杂度至少降n。我们把x与要求的限制p比较,然后就可以知道斜率k应该变大还是变小才能到达f§,二分斜率,就多一个log,所以我们优化了时间复杂度。这里有几个注意点,一个是如果凸包有一段是连续的,也就是有几个k相同,我们可以知道这就如同二分一个非严格递增的数组,稍微把二分写严谨一点就可以了。还有如果所有值都是整数,那么有 a b s ( f ( x ) − f ( x − 1 ) ) > = 1 abs(f(x)-f(x-1))>=1 abs(f(x)f(x1))>=1,那么相邻两段斜率差整数,所以二分k也就只用精确到整数。如果计算过程有小数,那么当然二分k要精确到小数。

例题

lg8544 禁断之门对面,是此世还是彼世

首先考虑到相邻行之间不同的条件下,我们可以使第n+2行与第n行相同,这样子就满足了两两相邻行之间的贡献都最小,所以只要考虑两行,然后乘n-1即可。我们考虑若 b [ i ] [ j ] b[i][j] b[i][j] b [ i + 1 ] [ j ] b[i+1][j] b[i+1][j]连边,形成了若干环和链。首先显然的trick是如果有一个链/环与另一个链/环之间形成交错(将点编号放在一条数轴上),也即有一个环或链的所含点编号不连续,就可以通过一些重排来实现编号的连续,并且一定不劣(这个比较常见)。然后如果一个环的大小超过3,就一定可以拆为若干个更小的环且答案不劣,所以环大小只有2或3。设计DP状态 f [ i ] [ j ] f[i][j] f[i][j]表示考虑了前i个数,已经形成了j对的最小代价,那么有三种转移,要么i+1不匹配,要么成环,可以暴力枚举环长,要么成链,可以用一个前缀和优化解决,共O(mt)。考虑这里t相当于一个"恰好"的限制,考虑用wqs来优化,我们发现原命题等价于一个二分图最小权匹配问题,所以随着t增大必然是一个凸壳,所以可以使用wqs二分,时间复杂度O(mlogt)。

slope trick

一些简单的部分跳过,主要讲如何实现。我们把凸包一分为二,变成两个单调的部分,用两个堆分别维护两个单调的部分的转折点。举个例子,如果序列为1 2 4 8,那么斜率为1 2 4,所以我们考虑在堆中放入坐标1 2 3 3就形象地体现了斜率,那么凸包的形态就存下来了。接下来以U字形凸包为例讲解各操作。对于左移右移操作,这个相当于一个全局加,我们可以两个部分分别一个全局tag来实现。对于加上一个新的v字形(|x-p|),我们发现,取出左半边最右坐标l,右半边最左坐标r。如果p<l,那么要把l弹掉,同时在左边右边分别压入一个p,如果l<=p<=r,那么在左边右边分别压入一个p即可,如果r<p,那么要把r弹掉,同时在左边右边分别压入一个p。我们发现我们有凸包的形态,却没有其纵坐标,可以储存最低点的位置,然后在各操作进行时更新最低点的纵坐标即可,更新的方式比较简单,建议自己推。

但是这个凸包并不能维护所有的操作,比如对应位取max或min,还有做(max,+)卷积等都难以实现。所以引入另一种实现方式,我们首先以只有左半边的,上凸的为例。我们将函数视为多个向量按照极角排序后相连的结果,储存每个向量的x和斜率,这里要用一个平衡树,以斜率为值排序,然后就可以用平衡树二分支持询问x所对应的段。那么左移右移同样可以由tag实现。这种一般不会加v字形,由于这样大概率会破坏其上凸性质,而斜率全局加(v字形的位置足够偏所以不会影响上凸性质)也可以用tag维护。对应位取max或min(对于上凸凸包大概就只有取min有意思)的话大概不会影响上凸性质,如果要做的话就是一个启发式合并,一次考虑一个凸包的每一段,然后二分出其所占据的左右端点,这里的二分是由于另一个凸包的斜率单调减小,所以只会有两个交点(理解为一条线割一个凸包),然后暴力更新就好了,三个log,有一个是平衡树获取在哪个段上。考虑优化,这个我在nfls-NOI2023-div2模拟赛56-T1中提出过,就是首先模糊化凸包,把每一段以右端点为y值变平,然后这个模糊化的在大部分操作下是可以不用平衡树维护的,在这个上面二分得出经过了哪两个段,然后在这两个段上二分,可以得到交点,过程中就将平衡树复杂度与二分分离了~~(但是真的好难写,臭不可闻)~~。考虑(max,+)卷积操作,可以说这才是这种维护方式的精华,考虑这个相当于做一个闵可夫斯基和(不会请自学),其本质就是向量重按极角排序合并,那么就可以直接启发式合并,两个log。对于特殊问题,可以不用获得x的对应段,可以改平衡树为堆或可并堆,可并堆的话复杂度就是一个log,第二个例题就是如此。

lg4272 序列变换

发现就是一个slope trick的板子题,可以先列出两维的DP,然后视一维为凸包即可。

lg9021 Subtree Activation

首先这是一个csy给出的,基于slope trick的,过度麻烦的,思维难度极高的,时间复杂度极劣的做法。相比标算没有任何一个地方比较优秀,除了思维自然

我们考虑u和v,如果u和v是祖先后代关系,那么从二者间就可以减少一个min(sz[u],sz[v])的代价,所以考虑 a n s = 2 ∗ ∑ s z − m i n ( ⋯   ) − ⋯ ans=2*\sum sz-min(\cdots)-\cdots ans=2szmin()。考虑到把每个逐一实现要求的过程写成一个序列,那么就是相邻两个如果是祖先后代关系就可以贡献一个 − m i n ( s z [ u ] , s z [ v ] ) -min(sz[u],sz[v]) min(sz[u],sz[v])。所以考虑线头DP,在后代处计入贡献,在祖先处匹配,记 f [ i ] [ j ] f[i][j] f[i][j]为第i个点,子树内还有j个已产生贡献的线头还未匹配的最大 ∑ m i n ( ⋯   ) \sum min(\cdots) min()

考虑树形DP,我们需要做的首先是子树之间的(max,+)卷积,此时我们的闵可夫斯基和就派上用场了。然后在父亲处,考虑每个点两侧有两个线头,所以必然一个用于接收,一个用于接收或产生贡献,不能有两个产生贡献是由于不可能从一个祖先走到它又走到另一个祖先,这样显然不优。我们这样子做,第一步,f[i-1]=max(f[i-1],f[i])=f[i],第二步,f[i+2]=max(f[i+2],f[i]+sz[x]),第三步,f[i-1]=max(f[i-1],f[i])=f[i]。第一步和第三步是容易的,把堆中最小的拿出来其x减1或把整个pop了就可以了。第二步可以发现如果sz[x]+f[0]>=f[2]的话,又这个是一个上凸的凸包,就可以除了f[1]处特殊处理以外,直接f[i+2]=f[i]+sz[x],这里相当于弹出堆顶(特殊处理f[1]),再在堆里插入几段(画图,可见文件夹中附图)。

我们下证明sz[x]+f[0]>=f[2]。首先既然有f[2],说明是多了两个子树,如果两个子树不是祖先后代,那么显然相加<=sz[x],否则由于上一次的第二步和第三步合在一起可以理解为第三步把x子树中除去x的最大的sz必然已经弹掉了(也可能本来就没有,弹了一个相对小的),这两个之中只有可能都是其后代或者都不是。如果都不是那一个的后代,那么大一点的一者也必然<=sz/2(因为大一点的一者是次大,最多sz和最大的同样为(sz-1)/2),所以二者相加<=sz/2。如果都是那一个的后代,我们可以观察那一个是怎么转移过来的,可以发现同样必然已弹子树中除了自身以外的最大sz,再对是否是这一个的后代展开讨论,就回到了这个讨论的开头,最终必然归入前一种情况。

所以我们发现我们的凸包只用对头进行操作和打tag,所以闵可夫斯基和可以直接可并堆做。

hdu6757 Hunting Monsters

我们先来贪心一圈。

首先一定是先打可以加血的。然后考虑给加血的排序,我们发现有能打的一定尽量打,可以就按照a排序即可。再考虑给扣血的排序,一个常见的trick,就是先研究给两个排序。我们设为 a i , b i , a j , b j a_i,b_i,a_j,b_j ai,bi,aj,bj,然后i在前所需的最小血是 m a x ( a i , a j + a i − b i ) max(a_i,a_j+a_i-b_i) max(ai,aj+aibi),j在前所需的是 m a x ( a j , a i + a j − b j ) max(a_j,a_i+a_j-b_j) max(aj,ai+ajbj),首先显然max中后者比前者大,比后者大小即可,所以我们一眼看出按b降序排序即可。这里有一个更聪明的方法,就是把这个过程看为一个函数,然后将其左右翻转,可以发现就是a和b反了,所以反过来时是按b升序(用之前贪加血过程理解),翻回来就是按b降序,这也正是打小怪兽题目的精髓方法。

排好序后,对加血和扣血部分分开处理,然后一个双指针贪心处理类卷积即可,感觉这部分不是很难,不再赘述。加血部分加的一定是一个前缀,所以随便做。扣血部分我们发现如果正着做有两个量要dp,一个是当前的所需初始血量,一个是还剩多少血量,发现两个量毫无关系就十分难做。所以我们反过来看打怪函数,这样就只用记当前所需的血量,注意这样是要先减b再加a。首先提出一个合并monster的方法,就是 a = m a x ( a i , a i + a j − b i ) a=max(a_i,a_i+a_j-b_i) a=max(ai,ai+ajbi) b = b i − a i + b j − a j + a b=b_i-a_i+b_j-a_j+a b=biai+bjaj+a,且感性理解发现合并顺序不影响最后结果(不详细证,大概暴力列一下三个怪的情况后就可以数学归纳了)。我们既然倒着DP,那么就只用第一条,也就印证了只用记a这个优势。DP状态为 f [ i ] [ j ] f[i][j] f[i][j]表示后i个数选j个合并出的最小a。

考虑优化,给出的第一种方法是edu的,碰到这种可以猜结论,比如一个怪会在一个i这维的后缀被选,感性理解是打的怪多了,应该在打怪清单中加新怪兽,而不会把原来打怪清单的一个换掉。又由于我们不知道这个凸壳的具体模式,所以有一种暴力维护凸壳的方法,用一个treap维护f数组,二分出分界点,然后分界处插入一个数,右边一段打一个tag,这个tag就是一个怪兽,支持合并,所以复杂度正确。

还有一种更科学想法。考虑扣血一段,写出转移式 f [ i ] [ j ] = m i n ( m a x ( 0 , f [ i − 1 ] [ j − 1 ] − b ) + a , f [ i − 1 ] [ j ] ) f[i][j]=min(max(0,f[i-1][j-1]-b)+a,f[i-1][j]) f[i][j]=min(max(0,f[i1][j1]b)+a,f[i1][j]),个人感觉csy老师接下来讲的有一点漏洞,给出完善后的想法。如果 f [ i − 1 ] [ j ] ≤ b f[i-1][j]\leq b f[i1][j]b,又有 b ≤ a b\leq a ba,所以之后的 f [ ∗ ] [ j ] f[*][j] f[][j]值就一直保持不变。考虑剩下部分,有 f [ i − 1 ] [ j ] ≤ b f[i-1][j]\leq b f[i1][j]b,考虑到如果作为第一部分, m a x ( 0 , f [ i − 1 ] [ j ] − b ) + a = f [ i − 1 ] [ j ] − b + a max(0,f[i-1][j]-b)+a=f[i-1][j]-b+a max(0,f[i1][j]b)+a=f[i1][j]b+a这个又和 f [ i − 1 ] [ j + 1 ] f[i-1][j+1] f[i1][j+1]取min,所以就是一个类似背包的东西,必然有凸性。考虑一个特例,就是 f [ i − 1 ] [ j − 1 ] ≤ b f[i-1][j-1]\leq b f[i1][j1]b f [ i − 1 ] [ j ] ≥ b f[i-1][j]\geq b f[i1][j]b,我们不难发现这样子相当于一个转折点,必然只存在一个,可以特殊转移。复杂度保证了,但是凸性如何保证?我们不难发现这相当于下凸函数的第一个点向上移了一点,首先由于f数组的定义,显然是超不过第二个点的高度,而第一个点和第二个点的斜率只会相比背包转移下降一些,所以下凸是可以保证的。那么我们就用堆来维护未变为常值的一部分即可。这个做法给出了凸性,这样子类似背包的东西,恰恰就证明了上一做法的结论(背包正是随着容量变大不会变换之前拿的物品)。

contest 861 DP专题

A

感觉还挺厉害的(?

首先想了很多容斥,最后发现了一种。我们来容斥第三个东西。首先由于元素两两不同相当于1-n的一个组合数,然后对于选出来的相邻两个,有可能间隔了1,2,3,4,>=5三种情况,枚举一下就是 O ( 5 11 ) O(5^{11}) O(511)。这里方案数的计算用组合数,1,2,3,4都可以通过将总数减去某一值然后将二元素合并,>=5可以先减掉4,相当于强制隔开,然后用组合数求解。然后考虑在这个已有的东西上面DP,我们储存上1,2,3,4个中每个是否是一个线头,然后考虑接入线头,同时容斥,这里 O ( 2 4 ∗ 4 ∗ 12 ) O(2^4*4*12) O(24412)。总共就是 O ( 5 11 ∗ 2 6 ∗ 12 ) O(5^{11}*2^6*12) O(5112612)。发现跑不动,开始优化。我们来枚举考虑间隔的过程,发现每次的一个修改只用更新之后的DP数组,于是复杂度降到 O ( ∑ i = 1 11 5 12 − i i ∗ 2 6 ) O(\sum_{i=1}^{11}5^{12-i}i*2^6) O(i=111512ii26),大概小于 O ( 5 11 ∗ 2 7 ) O(5^{11}*2^7) O(51127)。然后进一步优化,考虑到对于每一个f大部分的都为0,就尽量跳一些无用转移,我们考虑有几个与自己距离<=4,然后能够写出 O ( 5 11 ∗ 2 3 ∗ ( C 4 4 ∗ 2 4 / 5 4 + C 4 3 ∗ 2 3 / 5 3 + C 4 2 ∗ 2 2 / 5 2 + C 4 1 ∗ 2 / 5 + 1 ) ) O(5^{11}*2^3*(C_4^4*2^4/5^4+C_4^3*2^3/5^3+C_4^2*2^2/5^2+C_4^1*2/5+1)) O(51123(C4424/54+C4323/53+C4222/52+C412/5+1)),大概是 O ( 5 11 ∗ 2 4 ) O(5^{11}*2^4) O(51124)。然后就差不多可以过了,但是由于卡常太用力,可能细节比较多。对于时间复杂度那一部分分析,感觉漏洞很多(?),将就这理解知道可过即可。

B

wqs二分可以在DP优化专题中学习。

这道题我们发现随着b的递增是一个凸包,用wqs二分就可以轻松 O ( n 2 l o g n ) O(n^2logn) O(n2logn)。但我们可以进一步优化,发现每个点的价值为:

1. a b   p i + u i − p i u i − k 1.ab\ p_i+u_i-p_iu_i-k 1.ab pi+uipiuik

2. ! a b   u i − k 2.!ab\ u_i-k 2.!ab uik

3. a ! b   p i 3.a!b\ p_i 3.a!b pi

4. ! a ! b   0 4.!a!b\ 0 4.!a!b 0

所以新增一个a的价值就是 m a x ( p i + u i − p i u i − k , p i ) − m a x ( u i − k , 0 ) max(p_i+u_i-p_iu_i-k,p_i)-max(u_i-k,0) max(pi+uipiuik,pi)max(uik,0),然后贪一下,排序然后去前a个即可,顺便可以算出用的b数量,再加上wqs就是 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)

C

首先站在自己的视角,为了让乌龟尽量劣,我会第一行单调增,第二行单调减。

再次站在乌龟的视角,相当于上下一对 a i a_i ai b i b_i bi我可以选一个,那么我们考虑调整法,考虑向旁边挪多了什么少了什么,我们发现如果向一边一下挪可以多价值,那么再挪一下也一定可以多价值,可以画图理性理解一下,是由于我们的策略所致,所以乌龟一定是走到底然后下,或下然后走到底。所得相当于 第一行 m i n + 第二行 m i n + m i n ( 剩下分为两半的大的一半 ) 第一行min+第二行min+min(剩下分为两半的大的一半) 第一行min+第二行min+min(剩下分为两半的大的一半)

然后考虑背包,首先第一行min与第二行min中有一者必为全局min,不妨设是第一行min。然后考虑对于一个状态,那么我们把第二行min与submin位置互换,发现Sa+min2和Sb+min2中有一个值不变,有一个变小,所以必定不劣,所以第二行min为submin。把这两个去了,然后我们做一个DP, f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示考虑到第几个数,用了几个第二行数,和之差为多少的bool。

D

考虑一定是一个弯钩+一段+一个弯钩。对于弯钩,我想到的是用z函数,但是其实用hash就可以了。中间一段就是一列上两个一起去转移,先相互贡献一下,再向下一对贡献一下。

E

总是E最难

我们考虑转化命题,为钦定某几位为1的方案数,然后到时候子集容斥一下就好了。考虑把钦定的01串中连续段1抽离,发现这些段随意排列位置方案数是一样的,由于这是全排列。然后先进行一个整数划分,有约300种情况。然后我们DP, f i , j f_{i,j} fi,j表示点集状态为i,最后一个加入的为j的方案数,就可以得到每种长度的方案数。然后根据整数划分进行一个或FWT,然后结果全1的就是好的,然后排列下(这里需要一点组合能力,相对简单,略)就知道方案数了。注意如果直接FWT就是 ( ∑ 每种整数划分段数量和) ∗ n ∗ 2 n (\sum每种整数划分段数量和)*n*2^n 每种整数划分段数量和)n2n比较慢,可以预先将每种长度FWT预处理,然后在dfs整数划分时加入一个整数就对应乘一个FWT,这样就快多了,然后在最后时,由于只需要全为1的,可以改IFWT为简单容斥,就少了一个logn,然后就是O(能过)。

F

写过,略。

G

感觉就是一个树形DP(?)。考虑 f [ i ] [ j ] f[i][j] f[i][j]表示第i个点,是否需要割i与父亲的边的权值和最小值。然后在转移的时候就把所有儿子的f排序,然后取前几个这样子贪就好了。O(nlogn)。

H

神仙,首先题目中矩阵只能平移,被坑了好久。那么就是四个条件:

  • ∑ x i > 0 c i x i = ∑ x i < 0 − c i x i \sum_{x_i>0}c_ix_i=\sum_{x_i<0}-c_ix_i xi>0cixi=xi<0cixi

  • ∑ y i > 0 c i y i = ∑ y i < 0 − c i y i \sum_{y_i>0}c_iy_i=\sum_{y_i<0}-c_iy_i yi>0ciyi=yi<0ciyi

  • ∑ x i > 0 c i x i ≤ m \sum_{x_i>0}c_ix_i \leq m xi>0cixim

  • ∑ y i > 0 c i y i ≤ m \sum_{y_i>0}c_iy_i \leq m yi>0ciyim

那么用一种新奇的数位DP,从低位向高位考虑。记 f t , a x , b x , a y , b y , a , b f_{t,ax,bx,ay,by,a,b} ft,ax,bx,ay,by,a,b分别表示考虑到第几位,正x和进位了多少,负x和进位多少,正y和进位多少,负y和进位多少,前t位正x和是否满足<=m前t位,前t位正y和是否满足<=m前t位,然后就可以转移了。

I

首先考虑好数有几个,好数定义为存在它的倍数且不存在它的因数,首先31-60无倍数,不可。其次我们构造最小链覆盖 奇数 ∗ 2 k 奇数*2^k 奇数2k形式,有15个链,所以最长反链为15,所以好数最多15个。

接下来有两种解法。

第一种,考虑改为加点,当x有一个kx已加入时,x处于激活状态,然后就可以放肆加kx。我们用一个 f s , p f_{s,p} fs,p表示s(01串)中的数已激活,然后可以加入的有p个点,然后就可以转移了,共 2 15 n 2^{15}n 215n个状态,每个状态连向 O ( n ) O(n) O(n)个其他状态(考虑 s , s^, s,相对s改了哪一位),所以 O ( n 2 2 15 ) O(n^22^{15}) O(n2215)

第二种,将 a i ∣ a j a_i|a_j aiaj a i ∣ a k a_i|a_k aiak中j与k相连,考虑给除了好点的每个点标号,那么除了最大标号的点,其他所有点至少要有一个相邻点权值小于它。这里考虑连通块,然后到时候贡献算到一起就可以了,考虑容斥,钦定有几个局部最大值。因为对于一个好数最多对应一个局部最大值,所以可以进行DP,考虑已经有了局部最大值的状态01串 2 n 2^n 2n个,还有一共有几个局部最大值,转移时枚举新加入的局部最大值,所以是 O ( n 2 2 15 ) O(n^22^{15}) O(n2215)

J

比较educative的题,考虑这个过程尝试扯到最大生成树上面,实际上也确实很像,就是有一个超级汇点,然后父连子表示爸爸邀请儿子进来。然后考虑贡献,我们发现进去没有钱,而拉人有钱,所以考虑边权为 a i + a j a_i+a_j ai+aj,然后最后减去 ∑ a i \sum a_i ai。所以就变成了一个最大生成树问题。考虑Borůvka算法,我们对于每个树找到离它最近的树,然后合并,最多和 O ( l o g n ) O(logn) O(logn)次。我们考虑如何找到对于每个点离它最近,满足条件,不在同一树的点。可以使用全局的子集trick,也即对于每一个s,考虑s向s去掉某位1的 s , s^, s,转移, O ( 2 n n ) O(2^nn) O(2nn)可满足前两个条件,然后在考虑时维护min和submin,其中min与submin不在同一连通块,就好了,共 O ( 2 n n l o g n ) O(2^nnlogn) O(2nnlogn)

contest 868 DP题与计数

A

考虑怎么做到严格递增,那么就依次枚举用多少值的子集,通过转移顺序的固定来满足这一条件。然后考虑DP, f i , s , p f_{i,s,p} fi,s,p表示有i个集,已用为s,p为上一固定点,然后 n 2 3 n n^23^n n23n做就好了。

B

首先可以min-max+组合数(有范德蒙德卷积),然后推式子推出来,这里不展开写。

其次题解给出了一种解法。

E(结束时的期望抽牌数)=E(期望轮数)*E(一轮抽的牌数),这是由于每轮期望抽牌数相同导致的。

每张牌被一轮抽到概率是1/(m+1),所以期望是n/(m+1)+1(joker)。

而期望轮数就考虑第i张牌被抽到期望轮数,首先已经抽过的可以直接删了,然后这轮有新牌的概率是(n-(i-1))/((n-(i-1))+m),而抽到新牌不算轮数,所以期望是m/(n-(i-1)),而最后一张新牌要算轮数,所以总共mHn+1。

所以ans=(mHn+1)(n/(m+1)+1)。

C

一个抽象的字典树上DP,考虑 g x , y g_{x,y} gx,y表示在x和y两个子树中分别选若干数的满足条件(指后几位满足异或小于等于x的后几位)的方案数。这个看起来复杂度爆炸,但实际上是对的,分析一下。

1.x的d位为1,那么x和y的左儿子异或不大于x,x和y右儿子异或不大于x,所以只用考虑剩下的限制,那么就是x左y右dp值乘x右y左的dp值。

2.x的d位为0,那么x左和y右不可选,x右y左同理,所以就是x左y左+x右y右。

发现用类似dfs的方式,dp状态就是O(nlogn)个。

D

大便题,首先观察出只有两个单峰函数相错(不重叠),一个在上一个在下,且高度和为定值n或m,然后两种情况(蓝双单峰或黄双单峰)。然后我们枚举一个的高度,与两个函数峰处靠里的位置分别是什么,然后用一个插板列式子,再一个前缀和就解了。(具体看题解)

E

给出思路,考虑只保留一个对撞器它的周期,我们可以知道它放到一堆中,知道左右射出的比值与只保留一个时的比值相同,可以从后往前考虑,然后思考一下发现相邻两个左边向右射和右边向左射的次数一样,所以就好写了,下文略。

contest 872 树上

A

发现自己用了一个脑瘫的线段树+大力分讨直接麻烦了。所以有结论,就是dfn序排序,然后 ∑ d i s ( p i , p i % n + 1 ) / 2 \sum dis(p_i,p_{i\%n+1})/2 dis(pi,pi%n+1)/2就好了。

B

我们用一个常见的拆,有 φ ( x y ) = φ ( x ) φ ( y ) g c d ( x , y ) φ ( g c d ( x , y ) ) \varphi(xy)=\frac{\varphi(x)\varphi(y)gcd(x,y)}{\varphi(gcd(x,y))} φ(xy)=φ(gcd(x,y))φ(x)φ(y)gcd(x,y)。然后考虑莫比乌斯反演,记

f ( d ) = ∑ i = 1 n ∑ j = 1 n φ ( a i ) φ ( a j ) [ g c d ( a i , a j ) = = d ] d i s t ( i , j ) f(d)=\sum_{i=1}^n\sum_{j=1}^n\varphi(a_i)\varphi(a_j)[gcd(a_i,a_j)==d]dist(i,j) f(d)=i=1nj=1nφ(ai)φ(aj)[gcd(ai,aj)==d]dist(i,j)

F ( x ) = ∑ x ∣ d f ( d ) = ∑ i = 1 n ∑ j = 1 n φ ( a i ) φ ( a j ) [ x ∣ g c d ( a i , a j ) ] d i s t ( i , j ) F(x)=\sum_{x|d}f(d)=\sum_{i=1}^n\sum_{j=1}^n\varphi(a_i)\varphi(a_j)[x|gcd(a_i,a_j)]dist(i,j) F(x)=xdf(d)=i=1nj=1nφ(ai)φ(aj)[xgcd(ai,aj)]dist(i,j)

f ( x ) = ∑ x ∣ d F ( d ) ∗ μ ( d x ) f(x)=\sum_{x|d}F(d)*\mu(\frac{d}{x}) f(x)=xdF(d)μ(xd)

然后枚举x,那么就把 x ∣ a i x|a_i xai的数取出,然后跑个虚树就好了。

C

kruskal重构树上面,dfn序最大最小对应点的LCA与询问点的LCA便是,那么就用个线段树维护全局最大最小dfn即可。

D

首先一个想法就是把两个集合的操作二叉树建出来然后kdt上去就好了, O ( n n ) O(n \sqrt n) O(nn )

其次我们找出最大的清零时间,这就是一个线段树上区间max和单点查。然后再主席树维护操作3,支持区间加和单点查,查主席树上对应时间到现在的单点值。其中第二个主席树可以通过离线变为线段树。 O ( n l o g n ) O(nlogn) O(nlogn)

E

首先一个结论就是把两个节点对应节点对应,然后就是本来一样的不用删,剩下的删了必能加合法的,挺好证的。

然后考虑构造解,显然的是LCT可以切,这里给出O(n)解法。先把本来一样边对应点缩掉,然后每次在初始树上选一个叶子与父断边,然后连到该在的位置并把初始树上的叶删了。

F

先给出我的垃圾解法。我们通过点分树+并查集就可以把距离<=k的补给点全缩到一起,然后在原树上缩点缩掉,然后把这些点割了。发现如果有一个中转点合法,且有另一个点可以重新蓄力(也即有s,t,a,存在dis(lca(s,a),s)<=dis(lca(s,a),a)或dis(lca(t,a),t)<=dis(lca(t,a),a)),那么这个中转点与a距离<=k,矛盾。所以我们可以随便找一个可以重蓄力的点然后查一下能否作为中转点,然后给答案就好了。

但是还是太难写了,给出题解做法。我们首先以k为偶的情况,我们从每个点逐个bfs距离k/2的点,然后遇到已被占领的就并查集搞一起,分析一下O(n)。然后询问时,有x与y,如果距离<=k直接好,否则我们将x和y都在 p a t h x , y path_{x,y} pathx,y上走k/2,判一下走到的点是否在同一并查集即可,原理就是我的做法中最后一个结论。k为奇时就拆点使k变两倍即可。

G

看题解吧,有点长不想写。

H

给一个结论,就是把图黑白染色然后把镜子视为边,那么如果形成了森林且所有黑点位于同一树或所有白点位于同一树。考虑证明,首先是否有环等价每一段都被光线遍历。然后考虑画出光线路径与两侧的关系,发现一开始我有两个端点,一黑一白,之后就是黑点白点分别在路径上遍历,以白点成树为例,那么发现白点构成了一个树,因为边缘上的白点已经相互连通,而中间的白点想要被光线遍历到,那么只可能位于两个白点的路径上,所以所有点连通,所以构成树。而黑点类似,但是在每个白房子里构成若干黑树,所以得证。然后跑两遍矩阵树就好了。

I

考虑up是个什么,我们记上次的max与这次所选点之间的链之间抽出来然后从上一个到这个点按顺序排列加到末尾。为什么可以呢,因为当前submax和max链上的都删不掉,所以会在最后搞掉,同时可以把这些缩到一起,权值submax,所以不影响其他点的相对顺序。然后剩下的就是LCT了,我不会所以略。

J

解法1:

点分树,考虑就是一个点分树+动态开点权值线段树,但是修改涉及logn个线段树,又开logn个节点,所以就空间 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 n ) O(nlogn) O(nlogn)(详情可见点分树模板的空间分析)),否则空间压不到 O ( n l o g n ) O(nlogn) O(nlogn),时间都不允许。

解法2:

这个就比较edu了。

dist本质时depx+depy-2deplca,我们考虑算 ∑ d e p l c a \sum deplca deplca,当只有x与y时,可以x到root的边染色,那么y到根的染色边数就是deplca,所以可以树剖+主席树解决。考虑修改,发现时交换,那么只有一个主席树变了,更新一棵即可,时空双log,时空爆炸。

解法3:

也是比较edu,同时是正解。

考虑边分树,这里先引入可持久化边分树。因为边分树是二叉树,所以结构类似线段树,可以同理复制节点,也就可以可持久化,而点分树就不能可持久化。

转移到这题,就是考虑算贡献时就是在边分树上向上跳,设当前点为a,询问点为x,有别于x所在子树的a的子树整体为b, a n s + b c n t ∗ ( d i s ( x , a ) + v a ) + b s u m ans+b_{cnt}*(dis(x,a)+v_a)+b_{sum} ans+bcnt(dis(x,a)+va)+bsum,cnt指向位于[l,r]的节点数,sum指向位于[l,r]的节点到a的dis和。那么我们可以在边分树上每个点维护几个变量就能算了。类似解法2,将边分树可持久化,改成前缀相减,所以按照p的顺序把对应位到root的点更新,然后就好了。把操作改为重构一棵边分树。时空O(nlogn),过题。

contest 911 NOI真题

社交网络

解法一:

先n次dij+拓扑路径数,有总的,然后枚举中转点,删掉,n次dij+拓扑路径数,总共 O ( n 4 ) O(n^4) O(n4)

解法二:

跑出删掉每个点的floyd,然后枚举起点,终点,中转点,总共 O ( n 4 ) O(n^4) O(n4)

解法三:

跑出总共的floyd,然后对每个点求出最短路径拓扑图,倒着DP转移就可以知道经过每个点的方案数,总共 O ( n 3 ) O(n^3) O(n3)

星际旅行

这题贪心正确性未知(问了NOI队爷也证不出,关键在于若视为费用流模型为何不会退流),想知道结论是什么可以看题解。

变换序列

解法一:

考虑匈牙利增广,强制就相当于问有无增广路,然后随便搞搞就 O ( n 2 ) O(n^2) O(n2)

解法二(极度优美):

考虑将一个点对应的两个点间连一个无向边,无向边指向谁就是选谁。如果有森林,必无解。否则环上简单定向即可得到最优解,O(n)。

诗人小G

写过,跳。

植物大战僵尸

写过,跳。

管道取珠

所以发现平方相当于两两相同的给一个贡献,然后DP,一维表示考虑第几个,一维表示第一个第一管用了几个,一维表示第二个第一管用了几个,随便转移就 O ( n 3 ) O(n^3) O(n3)了。

海拔

可以证明必为一块0,一块1。(证明略)

然后相当于切一刀,建图跑最短路即可。

最短路径问题

典型的在线段树上维护左右6个两两距离。

然后合并时,标号四列为1234。中间12个floyd一下, O ( 1 2 3 / 2 ) O(12^3/2) O(123/2);右侧两列必为1列取一,走到2列取一,再走到2列取一, O ( 6 3 ) O(6^3) O(63)。同理左侧两列。然后1与3,2与4也类似。1与4就是1走到2走到4。共 1 2 3 / 2 + 5 ∗ 6 3 = 1944 12^3/2+5*6^3=1944 123/2+563=1944。再一个log,大概能过。

产品销售

建出图,然后从1-n依次增广,用满流一侧为源。

考虑三类边,一类向右,一类向左,一类右的反悔。然后两个线段树维护区间最小值,向左和向右,还有一个维护有几个反悔边。然后顶到反悔上限或源流量上限或汇流量上限为止。O(nlogn)。

contest 912 贪心

A

好像一年前的题。。。真越学越菜。。。

所以考虑一直往一个奖池里放票,那么收益差是递减的,没有修时,就是每次选受益最大投即可,证明显然。因为有”保证你在每个奖池中押的彩票数不能超过该奖池原有的彩票数“这一条件,所以修了之后,收益变化,但是最多回退一张重塞或最多从别的那里偷一张,证明显然(运用 a b < a + 1 b + 1  当 a ≤ b \frac{a}{b}<\frac{a+1}{b+1}\ 当a\leq b ba<b+1a+1 ab)。

B

Hint:有源汇上下界最大流

考虑建图,首先考虑全部染贵的颜色,然后改便宜,为最大流。S与行限制点连边,限制点与对应直线的点连1边,然后T与列限制点连边,限制点与对应直线的点连1边。然后上下界是易得的。

C

基本思路简单,就是DP, f i , l , r f_{i,l,r} fi,l,r表示第i行左侧少l个,右侧少r个,以上都合法的概率。转移显然,然后加前缀和优化等就达到时空 O ( 150 0 3 ) O(1500^3) O(15003)

过不了,考虑优化。思考前缀和优化过程,从反面考虑,发现就是i+1行r小于i行l或i+1行l大于i行r为非法,发现转移特征量少了一个,就感觉DP能少一维。然后列式子,举一个例子,以当前行(i+1)左侧少了x个,且只考虑上一行r小于此行l,那么总概率为 C k x p x ( 1 − p ) k − x g m − x ∑ j = 0 m − x − 1 C k j p j ( 1 − p ) k − j C_k^xp^x(1-p)^{k-x}g_{m-x}\sum_{j=0}^{m-x-1}C_k^jp^j(1-p)^{k-j} Ckxpx(1p)kxgmxj=0mx1Ckjpj(1p)kj,其中 f i f_i fi表示上一列左侧少了i个的总概率, g i g_i gi表示上一列右侧少了i个的总概率,发现左侧一块好搞,右侧只与j有关,一个前缀和优化即可。然后其他几种情况列出来会发现同样十分好处理(两个变量独立求值相乘,用个前缀和都结了)。

再滚存,就时间 O ( 150 0 2 ) O(1500^2) O(15002),空间 O ( 1500 ) O(1500) O(1500)

D

好像做法被题解碾压了。。。

我们加强互斥与同一条件使得只要满足互斥与同一条件就满足所有条件。一类,是本来的互斥。二类,是区间无交集。三类,是下界之和大于T或上界之和小于t需要强制在同一格。我们发现这三类就是充要了(感受一下),然后二分染色即可。

但是图稠密了,时间不允许,考虑优化。一类,暴力二分染色。二类,用几个set,一个是存两种色的已有色的l,然后异色set找有无>r的,l同理,再有个无色set,就可以得到新染点,染+dfs即可。三类,同二类,就是set运用方式改下。

所以一共用 3 ∗ 2 3*2 32个set,时间常数 2 ∗ 3 ∗ 2 2*3*2 232,再一个log,大概能跑。

题解:

真的强,%%%。

就是复述了,考虑n1=minr,n2=maxl,以此为起点开始干。

三种情况。一种是有三个两两不交,就无解。一种是两两有交,以要尽量大为例,那么顶上去显然有一个会顶到n1,另一个就是n2向上调。一种是非两两有交,那么可以知道若一组正取n1,另一组正取n2,那么n1无法增大,也即minr对应老师若去2组就不合法了,那么若要尽量大,发现是与情况二一致的。

考虑限制,那么就是通过以n1,n2为起点,下调1组人数,或上调2组人数。然后得到后用二分图染色验证是否合法。至于为何两组这样取最优,感觉懂了流程就感觉很对,不会严谨证。时空 O ( n + m ) O(n+m) O(n+m)

E

应该是最重磅的了。

看ppt吧。

F

首先把所有同色的看为一个块,然后每次就是把每个块的首元素减一。那么我们干脆进行min块大小次数,使一个块没了,然后在全局tag中记要删几次。之后把这个块的两侧合并,同色,能删则删(因为可能涉及新的块中有一元素减了部分),合并。重复此过程,O(n)。

G

时隔一个月又碰到了,看完题解之后感觉这个想法很难维护,而且细节很容易挂,所以在“IOI2020国家集训队作业”里面给出了另一种解法。

又想了一下发现全部假掉,虽然可以改对,但是不如使用正解,所以请看“IOI2020国家集训队作业”里面给出了另一种解法。

固定随便一个直径,然后除去直径剩下若干树,对于每个树每次取出最长链扔到set里。

我们分类考虑,第一类y=1,那么是取过x的段与剩余的大段。

第二类y=2,如果在直径上,那么就是归于第三类,否则取直径与过x的段与剩余的大段。

第三类就是取直径,过x的段,与一堆大段(此处可以处理出来每个的权扔到set里,注意讨论过x的是否误记)。

这里可能有一条链误算,即不含x同时不过直径,但是可能更优,但是经过思考,因为有直径,过x的段,剩余段三部分,完全可以用剩余段干进去,然后从中再获益一个剩余段,得证无误。

H

比较厉害的数据结构。

解法一:

我们考虑这个流程,就是让每个变为 m i n ( m a x i = 0 x − 1 a i , m a x i = x + 1 x + 1 a i ) min(max_{i=0}^{x-1}a_i,max_{i=x+1}^{x+1}a_i) min(maxi=0x1ai,maxi=x+1x+1ai)(思考取min必优原因,此处略),然后每次是消掉一层的最大值。我们考虑一个流程,对于每个变过的点有三个状态,一个是未知向哪里取,一个是向前缀取,一个是向后缀取。首先get到一层的最左l和最右r。那么这层的显然都变1。l与r之间的1-3状态必然都变成了当前值,所以全部变1,同时又变了一次所以计入答案。然后l左侧的点,若为1那么变2,若为2那么不变,若为3那么变1同时记入答案。r右侧的点,若为1那么变3,若为2那么变1同时记入答案,若为3那么不变。总共O(nlogn)。

这个过程有点类似贡献移后计算,有点某种DP的味道。

解法二(更为通用):

考虑每个节点衰变几次,我们把这个数之前的染白,之后染黑,扔到数轴上,那么操作相当与跳到严格小于自身的最大黑白中较小一者。考虑用线段树维护进入当前区间走到白/黑点时,走出时的点及次数。然后直接好了O(nlogn)。

I

首先问题可以转化为叶子两两有交即可。

我们取出经过每个叶子所有的路径能到达的最浅深度对应的节点。显然如果这些点不是孩子祖先关系,就无解。否则取出所有中最深的一个,发现只要每个叶子的一个路能到达这个点那么就是合法的。

J

先排序,然后发现左边一段归左,右边一段归右。以左段为例,必然每次取最右两个合一,是左偏结构。这个证一下,用哈夫曼树的思路(可见《奇思妙想》的第一个)就好了。还可以考虑每个数的系数和固定,这样子刚好是越左端系数越大的极端情况。然后我们观察从一个已成型的左偏树中加入一个,发现变化量为 δ 2 n \frac{\delta}{2^n} 2nδ形式,所以考虑到大概与中心偏离了log级别的量时,就必然不优,因为 2 n 2^n 2n会将两侧偏移量拉的巨大。然后浮点数乘 2 n 2^n 2n转整型处理,发现是一段表示迁移的代价,然后一个最大前缀和就知道哪个最优。

K

sb构造根本不会。

先问CC,CH,CO,HO,OO,就可以知道1-n-1的C和2-n的O,以及2-n-1的H。然后要确定1和n的数,可以发现1可能为H或O,n可能是H或C,那么总共 5 4 + 1 ( n − 1 ) 2 + 1 n 2 \frac{5}{4}+\frac{1}{(n-1)^2}+\frac{1}{n^2} 45+(n1)21+n21,发现只有n=4不行,需要另行构造。

对于n=4,先问CH,CO,HH,HO,然后如果问出了一个,就暴力确定,如果没有,那么问OOO,CCC,如果问出,就暴力确定,否则只会是OOHC,OOCC,OHCC中一个,暴力确定。最大 1 4 ∗ 4 + 1 9 ∗ 2 + 1 16 ∗ 2 < 1.4 \frac{1}{4}*4+\frac{1}{9}*2+\frac{1}{16}*2<1.4 414+912+1612<1.4

contest 934 数据结构选讲

A

感觉和数据结构没有关系。

我们求出对于每个左端点,这样子一直跳跳到的最右位置,这个可以twopointer直接求出来,具体就是 f i = f j + 1 f_i=f_j+1 fi=fj+1其中j满足是i为左端点,j-1在满足条件下最大。

然后就可以枚举最左断环位置直接求了。

B

我们对于每个点,可以求出能够延伸的最左位置,然后直接一个扫描线+线段树即可。

C

直接用一个主席树,可以支持线段树上二分一段左端点固定,全部是1的区间,和比较两个线段树,第二个具体就是hash找到第一个不同位置。然后主席树+dij就好了。

D

题目又看错了,“最小化边集中的最大边权”就很简单了。

直接发现一个奇连通块显然不行,偶连通块每次可以同时翻两个,显然行。所以就反过来做,每次看看当前行不行,不行的话就加边并查集维护,然后由于要删边,还要线段树分治,O(nlog^2n)。

哎,再写一遍发现好多题原来都假了,正确解法写在“IOI2020国家集训队作业”。(或者说更加详细的)

E

二分答案x,>=x的赋1,否则赋-1,然后查询几条路径和>=0。那么我们就点分治,然后每次一个中心时,用逐一加入法和单调队列,注意逐一加入时要按照子树depmax从小到大,O(nlog^2n)。

F

我们考虑对于 a < c < b < d a<c<b<d a<c<b<d时, ( a , b ) (a,b) (a,b) ( c , d ) (c,d) (c,d)之间可以互相到达,那么我们可以把它们合并在一起,我们又想到剩下的只有包含的情况,所以我们用 ( a , d ) (a,d) (a,d)表示合并后结果是合适的。我们查询的时候可以直接查两个东西的并查集,然后看看这两个代表区间是否包含。

我们考虑怎么动态加入合并,我们发现如果每次加入,然后询问有哪些和加入的相交,怎么处理都会出现相含的没有去掉。又看到“加入的区间长度严格单调递增”,所以考虑反过来,倒着扫一遍,看看每个区间第一次被抹消在哪里,考虑相当于查询区间最小值(看看有哪个端点在里面)和单点赋值(大的区间左右端点),这是容易的。但是我们又发现新的区间又是没见过的,所以考虑构建一个从后向前扫的主席树,这样就能实时查询了。然后我们发现可以实时查询时,我们询问的区间并不是比之后的区间小的,然后仔细思考发现此时相含也是相交,因为前面如果是大区间,里面一定有若干端点,我们有一个比构成大区间的区间们大的小区间,肯定与这些区间们若干相交。(感受一下。。。)

G

并没有在老师讲之前想出来。

我们相当于将列视为数组,然后值是所在行数,然后相当于询问有多少个区间满足 m a x − m i n − r + l = 0 max-min-r+l=0 maxminr+l=0。我们考虑从左向右扫描线,然后用单调队列+线段树维护,发现有 m a x − m i n − r + l > = 0 max-min-r+l>=0 maxminr+l>=0,所以就是变成线段树维护最小值和最小值个数,感觉见过但是忘了,所以比较edu。

contest 936 计数选讲

A

我们一步步来,首先显然对于每种质因子是可以分开看待的,所以我们枚举每种质因子,这是O(n)的。接下来,考虑对于一种质因子,我们每个值对其有一个幂次,我们接下来都与幂次有关,设为序列c。那么我们考虑对于一个子序列,我们会取什么,显然想到的就是幂次的中位数。中位数这种东西比较抽象,最大化问题里面我们是把它二分,而计数问题,尤其是每个值要“走向它”,那么当然会想到P3286的trick。具体就是我们把所有子序列放在一起处理,然后开始扫描,从幂次0扫到logn,然后对于小于等于的数赋-1,其他赋1,这样和如果是正数就说明这个子序列中位数会随着扫描线向下跳一位。那么我们就做一个扫描线,维护整个序列-1个数和1个数,然后发现要计算的就是
∑ i = 1 c n t + ( c n t + i ) ∑ j = 0 m i n ( i , c n t − ) ( c n t − j ) ( i − j )     c n t + 表示 1 个数, c n t − 表示 − 1 个数 \sum_{i=1}^{cnt_+}\tbinom{cnt_+}{i}\sum_{j=0}^{min(i,cnt_-)}\tbinom{cnt_-}{j}(i-j)\ \ \ cnt_+表示1个数,cnt_-表示-1个数 i=1cnt+(icnt+)j=0min(i,cnt)(jcnt)(ij)   cnt+表示1个数,cnt表示1个数

其中i>=j可以发现就是i+k>=j+k,其中 k = c n t − − j k=cnt_--j k=cntj,所以就是 i + k > = c n t − i+k>=cnt_- i+k>=cnt,所以我们枚举i+k,可以发现方案数也即上式就是 ∑ k = c n t − n ( n k ) ( i − j ) \sum_{k=cnt_-}^{n}\tbinom{n}{k}(i-j) k=cntn(kn)(ij),也就是枚举k和i之后,i的那个sigma可以范德蒙德卷积公式算掉,然后发现再造一个 l = c n t + − i l=cnt_+-i l=cnt+i,那么 i − j = k − l + c n t + − c n t − i-j=k-l+cnt_+-cnt_- ij=kl+cnt+cnt,然后就好了,对于k和l分别计数,在把 c n t + − c n t − cnt_+-cnt_- cnt+cnt容斥掉。

B

我们考虑这里的k次要怎么处理,我第一个想到的是既然k怎么小,不如用“管道取珠”的trick。所以我们可以选j条边断掉,然后剩下的几个部分里面都至少要一个点(类似虚树的叶子)。所以接下来就自然设计了状态 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示以i为根的子树,一共断了j条边,i所在的子树有无已选点,那么我们就可以树形背包O(nk)做了。然后对于根位于“叶连通块”的情况中,我们特殊处理具体就是枚举叶连通块的割边,然后就是这个割边下面部分和上面一个点值的卷积,这个也是O(nk)的。然后最后乘一个组合数把k条边映射到j里面,应该是简单的组合数。(因为k次方拆开之后,会有高次方项,而我们这里j是不可重边集)

C

一样用"管道取珠"的trick,考虑把border变成周期,所以式子就是 ∑ i = 1 n − 1 ∑ j = 1 n − 1 k m a x ( g c d ( i , j ) , i + j − n ) \sum_{i=1}^{n-1}\sum_{j=1}^{n-1}k^{max(gcd(i,j),i+j-n)} i=1n1j=1n1kmax(gcd(i,j),i+jn)
∑ i = 1 n − 1 ∑ j = 1 n − 1 k g c d ( i , j ) = ∑ g = 1 n − 1 k g ∑ d = 1 ⌊ n − 1 g ⌋ μ ( d ) ⌊ n − 1 g d ⌋ 2 = ∑ g = 1 n − 1 ⌊ n − 1 g ⌋ 2 ∑ d ∣ g k d μ ( g d ) \sum_{i=1}^{n-1}\sum_{j=1}^{n-1}k^{gcd(i,j)}\\ =\sum_{g=1}^{n-1}k^g\sum_{d=1}^{\lfloor\frac{n-1}{g}\rfloor}\mu(d)\lfloor\frac{n-1}{gd}\rfloor^2\\ =\sum_{g=1}^{n-1}\lfloor\frac{n-1}{g}\rfloor^2\sum_{d|g}k^d\mu(\frac{g}{d}) i=1n1j=1n1kgcd(i,j)=g=1n1kgd=1gn1μ(d)gdn12=g=1n1gn12dgkdμ(dg)
分开两部分,我们稍微改一下,就是枚举gcd,然后枚举i,然后枚举j有一个上界,然后一样化简莫反式子就行了(lpz推了是可以的,最后可以枚举n和 n i \frac{n}{i} in n i j \frac{n}{ij} ijn,这三个范围,一共还是两个log)。

D

一开始想了一个O(nlog^2n)的分治NTT,但是发现劣了,所以不介绍,直接写一下新的想法。

我们首先知道这个限制条件相当于每个点有一个编号小于它的父亲。我们考虑n个点,每个点都尝试向前连边,那么方案数就是(n-1)!。我们考虑一些大小在限制条件的子树的并(森林)怎么做,我们容斥,计算出有一个大小比 n − 1 2 \frac{n-1}{2} 2n1大的树的方案数。接下来p表示一个大小p-1的森林,有 f ( p ) = ∑ i = n + 1 2 p − 1 ( p − 1 i ) ( i − 1 ) ! ( p − 1 − i ) ! f(p)=\sum_{i=\frac{n+1}{2}}^{p-1}\tbinom{p-1}{i}(i-1)!(p-1-i)! f(p)=i=2n+1p1(ip1)(i1)!(p1i)!,第一项是选出这个树的元素,第二个是组成第二棵树的方案数,第三个是剩下一部分的方案数,计算方法是p-i个点组成一棵树然后把根去了。所以 f ( p ) = ∑ i = n + 1 2 p − 1 ( p − 1 ) ! i = ( S ( p − 1 ) − S ( n − 1 2 ) ) ( p − 1 ) ! f(p)=\sum_{i=\frac{n+1}{2}}^{p-1}\frac{(p-1)!}{i}=(S(p-1)-S(\frac{n-1}{2}))(p-1)! f(p)=i=2n+1p1i(p1)!=(S(p1)S(2n1))(p1)!。所以我们就容斥出来了,我们考虑怎么合并一棵树和树外,然后我发现我不会合并。

给出听课后的想法,首先类似上面的东西,算出以i为根子树的大小>=(n+1)/2的方案数,这是容易的,然后有 a n s i = f i − ∑ j = i + 1 n a n s i i ans_i=f_i-\sum_{j=i+1}^n\frac{ans_i}{i} ansi=fij=i+1niansi,这里需要除i,是由于我们需要减掉的,是j在i的子树内的,而j连出去可能和1-i中的一个,所以除i。

E

感觉比较难?

首先用一些容斥可以把真子集限制改成子集。

我们这样子就变成在k个桶里面扔节点,求k从1-n-1。

我们倒着考虑,也就是i号表示倒数第i个,用 f i , j f_{i,j} fi,j表示i的子树,编号最大的在j号桶。考虑合并,我们发现有两种情况,一种是新加点位置>=所有子树的位置,这个是容易的,还有一种是有一个子树的位置>新加点,其他都<=新加点。我们枚举那一个的子树的种类是哪一个,然后考虑其他点<=新加点是容易O(n)的,然后做一个前缀和,总的计算就O(n)了,合并一共O(nk),所以总的O(n^2)。

contest 941 DP选讲

A

我们用 f i , j f_{i,j} fi,j表示可以操作了i次,现在左端点是j,那么可以处理的最长区间的长度是多少。

然后对于i>=1e4的可以看作一个状态,dp画决策树即可。

B

我们考虑每层都能染成一种颜色的话答案是maxdep,否则我们可以构造,一层层考虑,发现有一层的非叶子节点(cnt)的颜色肯定够用,因为说明有a+b>=2*cnt,所以cnt<=max(a,b)。然后如果叶子节点颜色不够用了,那么就把一种颜色染完,然后剩下只有一种颜色,可以使其他层都是同色,答案maxdep+1。

具体的,我们取每层节点数拿过来做booldp,然后就可以判答案是哪一个。如果是后者,那么就从上到下暴力染即可。

C

我们可以设状态 f i , j , k f_{i,j,k} fi,j,k表示考虑前i个,mex是j,还剩k个>j没用。

我们发现这个在转移的时候元素之间有一个组合数,同时种之间也有一个组合数,而且是很难统一的,我们又发现这里加入一个元素的转移是非常容易快速简洁的,所以我们用一种“平衡思想”,想办法让前者变简单,后者变难,这样可能可以达到“平衡”从而优化复杂度。考虑怎么做,我们发现前者的瓶颈在于需要有元素间的组合数和种之间的组合数,想办法把一个挪到后者来提前计算,发现对于种之间组合数,相对来说和加入“种"来提升mex的过程中更为紧密,所以考虑把元素之间的组合数提前计算。然后状态就变成了考虑前i个,mex是j,还剩k”种“>j没用,就可以快速转移了,对于mex提升过程转移可以用前缀和优化。然后我们发现把种之间的组合数挪后计算也可以,就是 f i , j , k f_{i,j,k} fi,j,k多含一个k!,转移中的前缀和优化就更为显而易见了。

D

感觉我的状态的转移下这题最多蓝?肯定我假了

考虑枚举根,然后我们把最后会和根接在一起做贡献的叫做有效边,我们发现答案就是 ∑ c n t i 2 i \sum \frac{cnt_i}{2^i} 2icnti。我们发现对于一条有效边,它到根的路径上都要比它先用,那么就变成一个标号问题。考虑 f i f_i fi表示i子树内(含i和fai的边)的序列种数,我们发现想要加入一条新的边的时候,由于要在这个序列里面的有效边之前,所以我们不妨引入一维表示当前序列最靠左的边的位置,那么加入一条边就变简单了。考虑合并,我们枚举 f i , j f_{i,j} fi,j f k , p f_{k,p} fk,p f i ′ , q f_{i',q} fi,q,考虑i和k和i’是固定的,枚举jpq三个量,再枚举q是由j转移过来还是p转移过来,就可以 O ( s z i s z j n ) O(sz_isz_jn) O(sziszjn),前两个是典型背包复杂度,所以一共 O ( n 3 ) O(n^3) O(n3)。加上枚举根,就是 O ( n 4 ) O(n^4) O(n4)

contest 943 概率

A

考虑对于每一个非陷阱点列出一个方程,然后高斯消元一下就可以得到以陷阱点为自由元的一些式子,形如 f i = f a 1 + ⋯ + c f_i=f_{a_1}+\cdots+c fi=fa1++c。然后我们就可以知道对于每个陷阱i出发下一次到达陷阱j的概率,然后就可以矩快了。

B

皮克定理:顶点为整点的凸多边形,面积=内部整点数+边界整点数的一半−1。

所以我们考虑每一条边,那么相比原来的,就会减少这条边和外面轮廓构成的多边形里的点,这些都用皮克算。考虑答案就是 S − ∑ s ( 2 c n t − 1 ) / t o t S-\sum s(2^{cnt}-1)/tot Ss(2cnt1)/tot,其中S表示原个数(含边界),之后枚举两点连线,s表示这个外部多边形点的个数(含边界),cnt表示除了外部多边形以外还有几个点, 2 c n t − 1 2^{cnt}-1 2cnt1是含这个两点连线的新多边形的个数,tot表示新多边形总个数。考虑cnt太小的时候就爆精了,所以可以知道这个两点连线的两点距离小于log的,可以直接枚举。

C

比较edu。

考虑拆式子:
a n s = E [ ( X − E [ X ] ) 2 ] = E ( X 2 ) − E ( X ) 2 = E [ ( a − b + c ) 2 ] − E [ a − b + c ] 2     a 表示点数, b 表示边数, c 表示环数 = E [ a 2 + b 2 + c 2 − 2 a b − 2 b c + 2 a c ] − E [ a − b + c ] 2 ans=E[(X-E[X])^2]\\ =E(X^2)-E(X)^2\\ =E[(a-b+c)^2]-E[a-b+c]^2\ \ \ a表示点数,b表示边数,c表示环数\\ =E[a^2+b^2+c^2-2ab-2bc+2ac]-E[a-b+c]^2 ans=E[(XE[X])2]=E(X2)E(X)2=E[(ab+c)2]E[ab+c]2   a表示点数,b表示边数,c表示环数=E[a2+b2+c22ab2bc+2ac]E[ab+c]2
我们考虑每一项分别计算,可以计算E[a],E[b],E[c]然后加一起平方。对于前面的同理。

考虑E[a],E[b],E[c]都是容易的,考虑上面几个。有全概率公式 E [ a 2 ] = ∑ i , j P [ i & j ] E[a^2]=\sum_{i,j} P[i\&j] E[a2]=i,jP[i&j],也就是可以对于每一对考虑发生的概率,然后相加就是期望。

E [ a 2 ] E[a^2] E[a2] E [ a b ] E[ab] E[ab] E [ b c ] E[bc] E[bc]为例:

E [ a 2 ] E[a^2] E[a2]:考虑枚举两个点相互贡献一个同时存在的概率,由于两个独立,所以两个点不同时的概率是 1 4 \frac{1}{4} 41,两个点相同时的概率是 1 2 \frac{1}{2} 21,那么一共就是 n ( n + 1 ) 4 \frac{n(n+1)}{4} 4n(n+1)

E [ a b ] E[ab] E[ab]:考虑枚举一个点一条边。

1.点和边相邻, 1 2 \frac{1}{2} 21

2.点和边不相邻, 1 8 \frac{1}{8} 81

E [ b c ] E[bc] E[bc]

1.环包含边, 1 2 c n t \frac{1}{2^{cnt}} 2cnt1

2.环和边有一个交点, 1 2 c n t + 1 \frac{1}{2^{cnt+1}} 2cnt+11

3.环和边无关, 1 2 c n t + 2 \frac{1}{2^{cnt+2}} 2cnt+21

反正最后这样拆开算之后,算的部分都是朴素的。

D

先证明一个结论,就是一定是一直随机,然后最后一次性购买。显然一开始是一直随机,这是由于 x ≤ c i x\leq c_i xci。考虑如果已经有了m个物品,那么随到一次新东西的期望花费是 n n − m ∗ x 2 + x 2 \frac{n}{n-m}*\frac{x}{2}+\frac{x}{2} nmn2x+2x,之后如果有一次不随机,那么一定是有 n n − m ∗ x 2 + x 2 ≥ ∑ c n − m \frac{n}{n-m}*\frac{x}{2}+\frac{x}{2}\geq \frac{\sum c}{n-m} nmn2x+2xnmc,然后只要可以证明:
n n − m ∗ x 2 + x 2 ≥ ∑ c n − m ⇒ n n − m − 1 ∗ x 2 + x 2 ≥ ∑ c − m i n c n − m − 1 \frac{n}{n-m}*\frac{x}{2}+\frac{x}{2}\geq \frac{\sum c}{n-m} \Rightarrow \frac{n}{n-m-1}*\frac{x}{2}+\frac{x}{2}\geq \frac{\sum c-minc}{n-m-1} nmn2x+2xnmcnm1n2x+2xnm1cminc
那么就可以说明一次购买后都是购买,有:
n n − m ∗ x 2 + x 2 ≥ ∑ c n − m ⇒ n n − m − 1 ∗ x 2 + x 2 ≥ ∑ c − m i n c n − m − 1 ⇑ n n − m ∗ x 2 + x 2 ≥ ∑ c n − m ⇒ n n − m − 1 ∗ x 2 − n n − m ∗ x 2 ≥ ∑ c − m i n c n − m − 1 − ∑ c n − m ⇕ n n − m ∗ x 2 + x 2 ≥ ∑ c n − m ⇒ n ( n − m − 1 ) ( n − m ) ∗ x 2 ≥ ∑ c ( n − m − 1 ) ( n − m ) − m i n c n − m − 1 ⇕ n n − m ∗ x 2 + x 2 ≥ ∑ c n − m ⇒ ∑ c − n ∗ x 2 ≤ m i n c ( n − m ) ⇕ ∑ c − n ∗ x 2 ≤ x 2 ( n − m ) ⇒ ∑ c − n ∗ x 2 ≤ m i n c ( n − m ) ⇑ x 2 ≤ m i n c \frac{n}{n-m}*\frac{x}{2}+\frac{x}{2}\geq \frac{\sum c}{n-m} \Rightarrow \frac{n}{n-m-1}*\frac{x}{2}+\frac{x}{2}\geq \frac{\sum c-minc}{n-m-1}\\ \Uparrow\\ \frac{n}{n-m}*\frac{x}{2}+\frac{x}{2}\geq \frac{\sum c}{n-m} \Rightarrow \frac{n}{n-m-1}*\frac{x}{2}-\frac{n}{n-m}*\frac{x}{2}\geq \frac{\sum c-minc}{n-m-1}-\frac{\sum c}{n-m}\\ \Updownarrow\\ \frac{n}{n-m}*\frac{x}{2}+\frac{x}{2}\geq \frac{\sum c}{n-m} \Rightarrow \frac{n}{(n-m-1)(n-m)}*\frac{x}{2}\geq \frac{\sum c}{(n-m-1)(n-m)}-\frac{minc}{n-m-1}\\ \Updownarrow\\ \frac{n}{n-m}*\frac{x}{2}+\frac{x}{2}\geq \frac{\sum c}{n-m} \Rightarrow \sum c-n*\frac{x}{2}\leq minc(n-m)\\ \Updownarrow\\ \sum c-n*\frac{x}{2}\leq \frac{x}{2}(n-m) \Rightarrow \sum c-n*\frac{x}{2}\leq minc(n-m)\\ \Uparrow\\ \frac{x}{2}\leq minc nmn2x+2xnmcnm1n2x+2xnm1cmincnmn2x+2xnmcnm1n2xnmn2xnm1cmincnmcnmn2x+2xnmc(nm1)(nm)n2x(nm1)(nm)cnm1mincnmn2x+2xnmccn2xminc(nm)cn2x2x(nm)cn2xminc(nm)2xminc
最后一个显然,所以命题成立。

然后我们用一个 f i , j f_{i,j} fi,j表示选i个物品,价值和为j的方案,然后随便算一下全概率公式就行了。具体就是把购买的过程拆成若干步,每次是买一个物品,那种优就采用哪种,我们计算出每个局面的概率,然后全概率即可。

E

我们算一下随机选三个点,询问结果dep在1,2,3,……的概率,然后会发现在2的时候概率最大(约0.4)。那么我们随机几次,这个概率就会变成一个二项分布,所以原本概率之间的差距就会变大(有 p i ( 1 − p ) n − i p^i(1-p)^{n-i} pi(1p)ni这项),所以就可以相信我们选次数最多的两个点,那么它们dep为2的概率是极高的。所以我们随420次,然后出现次数最多(由于概率>0.1,所以出现次数也比较多,不用担心“踩不准”)的两个点,然后它们就是根的两个儿子,接下来依次以每个作为root,那么lca=root的就是真实根。

DP与交互

CF468E

考虑图论建模,积和式就相当于一个行和列之间的完美匹配。

所以我们建出一个一边为行一边为列的二分图,连上边长为1的边,对于一些之间多连上a-1的边,可以发现对于有这些边的连通块,可以特殊计算,剩下部分可以直接乘一个阶乘解决。考虑怎么对于连通块计数,我们发现对于一个连通块,点数最多为边数+1,所以可以直接扫多的一侧,然后对少的一侧状压dp,可以达到 O ( k 2 k / 2 ) O(k2^{k/2}) O(k2k/2),还不能通过此题。我们尝试优化,再发明一种方法,我们发现可以对于连通块建成一个dfs树和若干非树边,可以枚举非树边的选择情况后一次dp解决,具体的dp形似背包,一共是 O ( 2 m − n + 1 n 2 ) O(2^{m-n+1}n^2) O(2mn+1n2)。所以我们分治,对于 n > 2 3 m n>\frac{2}{3}m n>32m的用后者,否则用前者,就是 O ( 2 k / 3 k 2 ) O(2^{k/3}k^2) O(2k/3k2)了。

CF1326F2

和contest 861 DP专题 E重了。

看了几个hints就想起来了,不赘述,转到上面那篇文章看。

CF908H

考虑怎么构建,发现对于A,就相当于要求两个点在一个SCC里面,对于X就要求不在一个SCC里面,由于一定是AOX里面一种,所以我们可以把是SCC的缩完后连成一个链就满足了所有的条件,因为要求任何两个点a和b之间必须有a->b或a<-b。考虑一个SCC肯定是一个环那么最优,然后在想一下就发现大小>1的SCC越少边数越少。首先不管大小为一的SCC,这些可以最后接在结尾。考虑用 f i , s f_{i,s} fi,s表示有i个树边,s能否连通,其中s是每一位表示一个大于1的SCC,这个个数是n/2级别的,先预处理每一个SCC能否和其他的合并,然后就可以 f 0 , s = f 0 , s   x o r   l o w b i t ( s ) f_{0,s}=f_{0,s\ xor\ lowbit(s)} f0,s=f0,s xor lowbit(s)来初始化,然后之后用 f i , s = ∑ s 1 ∣ s 2 = s f i − 1 , s 1 ∗ f i − 1 , s 2 f_{i,s}=\sum_{s1|s2=s}f_{i-1,s1}*f_{i-1,s2} fi,s=s1∣s2=sfi1,s1fi1,s2来推即可,这里不必有s1&s2=0,我们把条件放松了,但是显然没事,因为如果s1&s2>0,那么s1与s1&s2连通,s2与s1&s2连通,就说明s1和s2连通,直接有 f i − 1 , s 1 ∣ s 2 = 1 f_{i-1,s1|s2}=1 fi1,s1∣s2=1了。我们放松了了之后就可以改枚举子集为FWT,可以FWT过去后不IFWT回来,而是O(n)的求出特定的 f ∗ , ( 1 < < n ) − 1 f_{*,(1<<n)-1} f,(1<<n)1的值,所以只用FWT一次,在每层暴力算单点值,一共 O ( n 2 n / 2 ) O(n2^{n/2}) O(n2n/2)

CF1290D

最傻的一道,不清楚为什么没人写。(可能不屑)

我们首先对于 k / 2 k/2 k/2分块,然后就变成了有 c n t cnt cnt个元素, k = 2 k=2 k=2时的处理。考虑我们分别对于%1,%2,%3,……处理出若干同余的链,然后沿着这些询问,这样子就是O(cnt2)次查询了,而且显然的,对于每一个块,我们都曾经让它和前面的元素分别共处一室过了,具体的对于x和y,有x<y,当%y-x的时候,有先插入x再插入y,也就是对于每一个元素我们都知道和它的前驱有没有相同的。这样子是O(2n2/k)的。考虑精细化计算,也就是对于长为1的操作链显然是不必操作的,把这些去掉就是O(3n^2/2k)了。具体看实现,可能讲的比较抽象。

CF1810G

比较玄妙的题目,表示没有见过这个trick。

具体来说,我们有一种“终态放入到始态”的DP思想,,讲的清楚一点就是在始态的时候就计入终态的贡献,但是只有当当前的sta到达过目标后我们才把这个东西计入答案。具体来说,这一道题目我们设 f i , j , k f_{i,j,k} fi,j,k表示考虑了前i个元素,离目标还差j,是否到达过目标的权值,那么就有 f 0 , i , 0 = h i f_{0,i,0}=h_i f0,i,0=hi,转移就显然了。注意如果i<0,那么说明超过目标了,也就对应的最大前缀和比既定的大了,是不合法的(这个时候贡献不是 h i h_i hi而是 h i + 1 h_{i+1} hi+1与我们设计的相悖),所以赋为0。计算答案的时候就是 a n s i = ∑ f i , j , 1 ans_i=\sum f_{i,j,1} ansi=fi,j,1

希望这种题生平不要再碰到了,但是这个trick倒是非常有趣。

8.16 闲话

其实就是反思一下为什么最近的比赛全部打烂。

话说我4天4场比赛全部烂掉确实挺强的。

CF892 div2

首先动车晚点了导致没有及时开打。

最开始的4道题略微慢了一点,最后是1h解决的。

主要问题还是在E,最后在赛后1min调AC了,但是反观E的大水样子,可以知道从根本上是因为这一种trick没有见过,就是trick积累的不够。还有一点,就是赛时的时候太慌了,一开始想出了一个假做法,没有构造卡掉,但是当wa的时候非常明白自己应该假了,但是最后却开始写对拍来证明自己假了!!!这种做法是极度愚蠢的,花了30min+来证明自己做法假了,又在这个基础上写了两个假做法,并证明它们假了,感觉自己简直就是天才。。。所以说不要有个人迷信,自己假了那就是假了,不要在慌乱之中稍微有一个看起来对一点的假做法,就直接乱撞,这时候最好的方法就是保持理性,或者说直接全部推翻从头开始想,然后用一种感性证明把一系列魔改的假做法一起证伪。

AGC064

前两题的节奏非常好,但是第三题直接给我干不会了。赛时的时候看到1.5h过去只有个位数写CD感觉很稳,然后整个人就懈怠掉了,导致最后发现CD是水的,一车人把我踩了。还有就是赛时的时候想出了C的解法,最后也写完了,但是发现复杂度算错+人傻常数大直接跑了10+s。所以就是特别对于这种时长短+acm类型的比赛,每道题的复杂度都要想清楚,毕竟是没有部分分可以骗的,之后改成正解又要花时间,这一类比赛就要又快又准,没有时间让你花大把时间写假做法。NOI系列赛时也是一样,如果这一种做法写起来很麻烦,那么不如先把简单的其他题打了。还有就是发现简洁=常数小,所以thick twice后的简洁做法写起来简单,也更加不容易T,所以有时候不如想一下怎么实现比较简单。呜呜,升3dan又要等几周了。

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

打的不好评价。描述一下我有多屎,刚开始开了1011准备冲一发首A,然后发现结论假了,稍微想了一下就改对了,然后发现已经有十几个人过了,同时发现自己WA了,然后手捏数据测了30min没有找到hack,最后手捏了一个hack成功,发现是有一个地方n和m写反了,说明这些也都是要注意的(主要是我暴力和std的都写错了/cf)。然后滚回去写签到,在一道签到题上又卡了1h,最后发现自己dp的时候没有写f=min()而是直接f=(),导致挂飞了/cf/cf,没想到还能这样挂,长知识了。卡完这题之后又在另一道神秘结论签到上面卡了1h,其实背后的原因是自己懒了,不肯多手造几组来观察,而是在一些形如"x 1","x 1 1"这些过于简单的上面找规律,那规律显然假爆了,最后手算了"3 1 1"和"2 2 1"就马上看出规律了,还有就是自己手算"2 1 1"的时候算错了,导致一直干扰我,反正就是菜/cf/cf/cf。最后又再一次的在签到题上面卡了1h,这次是概率没有学好,还有自己实在是太想喷出题人了,所以导致题目理解花了30min,然后发现就是一道高精度模板,所以就是要静下心结合样例解释慢慢理解题目,不要暴躁。总结一下就是每一道签到题卡了1h然后把整场比赛咕完了/cf。总结一下错的因素:

  • n和m写反等细节导致的,同时手捏数据没有特意卡边角情况。
  • 对于一些平时不会错的地方并不留意。
  • 太懒了,没有多手捏几组找规律。
  • 太急躁了,没有静下心看题。

然后是应对措施:

  • 使用大黄鸭调试法,对于每一个细节,任何一点东西都先仔细的看一遍,典型的有:nm写反,ij写反,ab写反,minmax写反,min忘写。总之就是先认定自己一定有无数细节挂了,然后带有这样的心态去一点点的看,使用一种局外人看自己代码的心态(帮别人抓虫),不要认为“调了半天了,哪有错啊,是不是数据假了,不会啊这么多人过了,不想写了,明明自己就是对的啊,这里肯定对的,那么只能是这里挂了,不会啊这里也对的,都看5遍了,算了手捏几组,诶手捏都是对的,烦死了不想写拍,不如再捏几组,诶是不是hack了,哎数据造假了,哎不如再看一遍注意一下有没有细节写错,不会啊这个细节我之前看过,不会啊这里一定不会写挂。。。”好怪啊,一反应自己调题心态竟然可以一下子喷这么多,说明真的很不会调题,所以就是要杜绝“这里查过了”,“这里一定是对的”,“不想写对拍”,“不如手捏”几种想法。

  • 手捏的时候用比较能hack的,要及时止损,捏了一些不能hack就及时改用对拍。

  • 找规律的时候多造几组,最好直接写暴力程序找规律。

  • 注意要仔细认真的审题,多审几次,最好手模样例来加深理解。血的教训就是NOIPT3审题审错这件事。

CF893 div2

这场梦幻开局,18minA了三道题目,一开始还以为可以直接AK离场。

最后的时候D调了100min直接退场。

无语死,D的问题就是一开始的时候做法就是假的,但是没有管,同时捏不出hack,一直在查边角错和初始化问题,同时懒得对拍,直接炸飞。所以就是有一个地方自作聪明写了O(n)的假做法,放着O(n^2)的真做法不写。所以就是在写题的时候要有一种“从源头出发”的想法,有时候要质疑一下自己做法有没有假,特别是仔细的审慎了一遍之后,不要有一种“这里肯定是对的”的想法,要有一种“刚开始造做法的时候可能就没仔细想”的认知,从源头出发挑刺。

哎,A完D后15min就口胡了EF,话说如果D是一发过那还真可以AK。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值