2022.4

四月了啊...

推一首歌吧 当时小椿沿海边跑的时候的 BGM,经典青梅竹马打不过天降妹子

反正在家网课,就顺便停课了

改的都是简单题,难题都弃了

好菜啊

好像没有那种花一下午时间研究一个算法的耐心了

ε-(´∀`; )

4.1

T1

不算太难,不写了

T2

给你一个 n 个点的无向图,计数满足 K 个限制的生成树数量,每个限制是一个点集 Si,要求 Si 在生成树上的导出子图联通。

n500,K2000

生成树计数肯定是矩阵树定理。

考虑每一个限制 SiSi 的导出子图的边数 cnti|Si|1,且该限制被满足当且仅当取到等号。

我们考虑给原图每条边 (i,j) 赋上边权 w(i,j)w(i,j) 为同时包含 ij 的限制个数,我们发现这样,对于它的生成树 T,边权和 w(T)=cnti(|Si|1),等号取到当且仅当所有限制都被满足,所以满足条件的生成树就是最大生成树。

最大生成树就是经典做法了,忘了的话去看一眼 Luogu P4208 [JSOI2008]最小生成树计数

还有 w(i,j) 的计算用 bitset 优化一下就是 O(n2Kω)

总复杂度 O(n3+n2Kω)

T3

答案文件 10.1 K

长度为 n 的序列 a,你有从中选出 k 个区间,区间的权值定义为所包含数的和。要求 k 个区间能覆盖整个序列,并且权值和最大,求最大权值和。

n105,kn(n+1)2,|ai|5×104

首先是一些 key observation

若两个区间为包含关系,那么我们显然可以舍弃被包含的区间,然后选择当前未选择的区间中权值最大的。因为最多 n 个不包含的区间就可以覆盖整个序列,所以前 max(0,kn) 大的区间一定被选

进一步观察,假设最优解选择了前 x 大的区间 (max(0,kn)xk),此时剩下 m 个点没有被覆盖,那么剩下的 kx 个区间一定两两不相交,并且每个区间至少覆盖 m 个未覆盖点中的一个。因为,若两个区间 [l1,r1],[l2,r2] 相交,我们显然可以选 [l1,r2] 代替,再选择当前未选择的区间中权值最大的,一定不劣。

所以我们先选上前 max(0,kn) 大的区间,计算它们的权值和以及它们覆盖的位置,然后再找到第 max(0,kn)+1 到第 k 大的区间。这个可以二分权值,然后再用树状数组,set 之类的东西求大于等于当前二分权值的区间个数,覆盖位置,权值和等等,这部分复杂度就是 O(nlognlogV),但若干区间权值相同的情况真的是及其恶心。

然后我们逐个加入第 max(0,kn)+1 到第 k 大的区间,设当前未被覆盖的位置是 p1,p2,,pm,我们需要对每个 1i<m 求出 maxj=pipi+11sjminj=pipi+11sjsa 的前缀和),然后把这些值塞进 set 里,每次求出前 kx1 大的数的和,再加上 maxj=pmnsjminj=0p11sj 就相当于选出了 kx 个区间覆盖了所有未覆盖点。随着 x 增大,会有一些 pi 被删除,所以要动态维护那个 maxsjminsj 的值(插入,删除,查询前 kx1 大的数的和),搞一个 set 之类的数据结构就可以做了,这部分是 O(nlogn) 的。

据说还有 wqs 二分 + 线段树维护 DP 的做法,不太会...好像只有我写的题解做法还写了 10K

/tuu/tuu/tuu

4.2

T1

给你长度为 n 的字符串 S 和正整数 k,判断 S 的每个前缀是否形如 (AB)KAA,B 可以为空串。

n106

没一眼切是不是应该去死

枚举 i,判断 S[1..i] 是否能作为 AB,所以只需求 lcp(S[1..n],S[i+1..n])

后缀数组,哈希都可以,新学了一下 Z 函数,这样就可以 O(n)

周三没有模拟赛,复习一下字符串,写个字符串总结(flag

T2

这个是原题 CF1120D 加了一个求方案数,(其实上一题也是原题 CF526D)

所以就不写了

有 DP 做法,也有最小生成树做法(能不能求方案数?)(去看题解)

T3

ARC016D

这个二分很有意思的欸

题意很长不写了,总是是求期望,也容易列出状态转移方程

fx,j=min{f1,H+Hj,1+E(x,y)E(fy,jdy)}

边界

fx,j= (j0)fn,j=0 (j>0)

但这个是有后效性的,不过后效性只与 f1,H 有关,我们考虑钦定 f1,H=A,然后直接按方程转移,最后在看算出的实际 f1,H 是否等于 A

我们把这样计算出来的 f1,H 看成是 A 的函数 f(A),想一想就有 f(A)1,所以就有 [f(A)A]0 他是有单调性的,可以二分出 f(A)=AA,也就是答案。

至于这个 f(A)1 应该也可以感性证明,考虑按拓扑序归纳,考虑 A 减小了 dAfn, 不会变所以它的导数是 01fx,j 如果从 A+Hj 转移来那么 dfx,j=dA,如果从 fy, 转移来,那么 dfx,j=dfy,dA 也是成立的,所以就证明了恒有 df,/dA1

4.4

T1 水题,T2交互

T2

猜树题,你要猜一颗二叉搜索树(按编号),可以 query(x,l,r) 询问 x 的子树是否恰好包含 [l,r] 的点,询问次数是 2n

想到单调栈求笛卡尔树的做法,我们也考虑使用单调栈。

按标号顺序依次加点,栈中维护一条最右链,发现是可以一次询问出当前点是否在栈顶节点的右子树。

总之要想到单调栈。

T3

你要构造一个 n 个点的简单图,每个点的度数至少为 k,且图中所有度数为 k 的点不能相邻,最小化边数。

2k10,2k+1n1000

并不是构造题,因为重点在于求最小边数。

我们把点按度数等于 k 和大于 k 分类,设等于 k 的集合大小为 x,那么两部分之间有 kx 条边,等于 k 的点之间不能连边,大于 k 的点之间可以连边,设连了 y 条。

容易列出不等式 kx+2y(nx)(k+1),为了 y 最小,解出 y=min{12[(k+1)n(2k+1)x],0}。那么总边数 kx+y 就等于 min{12[(k+1)nx],kx}x(k+1)n2k+1(k+1)n2k+1 时取得最小值。

得到了 x,y 之后构造方案就很简单了。

4.5

T1

给你一棵树,然后三个操作:

  • 向集合中加入一个数
  • 删除集合中的一个数
  • 询问集合中 [l,r] 的数编号的节点到 x 的最小距离

n105,强制在线。

很显然的点分树,对每个点用线段树维护它点分树上的后代即可。复杂度 O(nlog2n)

T2

the same as 4.2 T3

T3

经过一个经典的卡特兰数模型 (fi=j=0i1fjfij1),问题转化成了求 maxi=lrv7[(2i)!/(i!i!)],其中 vp[x] 表示 x 的质因数分解中 p 的次数。

l,r10104

首先有

v7[(2n)!/(n!n!)]=i1(2n7i2n7i)=i1[2n7imod2=1]

进一步考虑什么时候才是奇数,我们发现当且仅当对于一个 i,存在 k 使得 n[k×7i(7i1)/2,k×7i1],所以我们把 l,r 转成 7 进制从高往低逐位考虑即可。

复杂度瓶颈是进制转化,所以是 O(log2r) 的。

好困,,所以写的好像很简略。

今天还行,三道题都是自己想的,不过赛时摸的有点多,就写了一道。

这几天题也不太难,天天都是一车 AK,不过跟我垫底关系不大。

4.7

T1

抽象出题意就是,给你一个长 n 的 01 序列,你可以进行 m 次操作,每次选择一个长 l 的区间全部赋成 0,求操作后最少剩下几个 1

n,m,l106

不要想贪心了,不要想贪心了,不要想贪心了,虽然看上去很对但它就是错的。

先考虑一个看上去没什么前途的 dp,fi,j 表示前 i 个数,进行了 j 次操作,最少的剩下 1 的个数。

转移很简单:fi,j=min{fi1,j+[ai=1],fil,j1},时间复杂度 O(n2)

关于这种有限制次数的问题,如果不限制次数,很容易求解最优方案,就要想到 wqs 二分

答案的凸性容易证明,所以通过 wqs 二分就做到了 O(nlogn)

T2

给你一个平面图,每次操作修改边权,你需要回答每次修改后的最小生成树,强制在线。

n,q105

首先肯定想到 LCT,如果是边权只能变小就非常容易了,但我们无法在一条树边变大后快速判断它还在不在生成树上。如果可以离线,可以通过线段树分治等做到 O(nlog2n),但即使这样,巨大的常数也是很难通过的。

考虑本题的特殊条件,实际上,平面图的最小生成树有下面的结论:

这真是太妙了,看完题解激动了好长时间。

平面图的最小生成树的补集是其对偶图的最大生成树

证明是容易的,把边集分成两部分后,平面图和对偶图两者任一个不连通当且仅当另一个中存在环,所以当两者都联通且不存在环(也就是在平面图和对偶图中分别形成一颗树),边数加起来恰好是 V1+F1=E

对于本题,我们用两个 LCT 分别维护原图和对偶图的最小生成树和最大生成树,改变一个边权时,如果是变小,用原图的 LCT 判断生成树是否改变,如果变大,用对偶图的 LCT 判断。

时间复杂度 O(nlogn)

T3

题意就是一个矩阵树定理,它的基尔霍夫矩阵(的 n1 阶主子式)是长这样的(w 是给定的权值,S=i=1n1wi

K=[S+1w1w2wn1wn1S+1w1wn2w1w2w3S1]

就是一个 n×n 的矩阵,求 |K|,不过 n220。(但保证了 n2 的次幂)

但这是一个循环矩阵,所以我们给它右乘一个范德蒙德矩阵(我数学菜,不知道怎么想到的,但乘完真的好神奇啊)

V=[11111ωnωn2ωnn11ωnn1ωn2(n1)ωn(n1)(n1)]

其中 ωnn 次单位根。我们先令一个函数 f(x)=S+1i=1n1wixk。然后发现 KV 是长这样的

KV=[f(1)f(ωn)f(ωn2)f(ωnn1)f(1)ωnf(ωn)ωn2f(ωn2)ωnn1f(ωnn1)f(1)ωnn1f(ωn)ωn2(n1)f(ωn2)ωn(n1)(n1)f(ωnn1)]

发现 KV 就是 V 在每列乘了 f(ωni),所以 |KV|=|V|i=0n1f(ωni),又因为 |KV|=|K||V|,所以我们要求的 |K| 就等于 i=0n1f(ωni)

直接 DFT 求出所有 f(ωni) 即可,复杂度 O(nlogn),好耶!

4.8

模拟赛直接摆烂,听完讲题 T2 直接弃

T1

给你长度为 n01? 构成的串 |S|

01 串序列 t1,t2,t3,,tn 的个数,要求:

  • |ti|=i
  • ti1ti 的子序列
  • tnS 将每个 ? 替换成 01 得到

998244353n250000

先来牛逼的转化题意

先不考虑 ?,从 tnt1 就是把 S 每次删一个字符,不过如果两中删法得到的序列相同,那么算同一种方案,所以我们不妨钦定删 0 只能删连续一段 0 的最右面那个,删 1 只能删连续一段 1 的最左面那个,也就是说,相当于每次找到一个 01 然后删掉其中的 01(再序列开头补一个 0,结尾补一个 1)。这样计数就不会重。

我们再每个两个位置中间加上分隔符,比如 101 变成 0A1B0C1D1,每次选择其中⼀个 01 删除的时候, 我们也把分隔符删除。那么每个分割符被删除的时间就是一个 0n 的排列,而 0 相当于它左面的分隔符先于右面被删,1 是右面先于左面。

0 换成 <1 换成 >,计数满足条件的排列,据说这是一个经典问题。

fi 表示考虑到第 i 个位置的方案,然后枚举前面 > 的位置容斥:

fi=0j<i,sj=>(1)cnti1cntj(ij)fj

稍微变形:

fii!=(1)cnti10j<i1(ij)!fjj!(1)cntj[sj=>]

现在它看起来就非常的卷积,于是分治 FFT 即可。

至于 ? 就是把序列分成若干段,每段分别计算,最后乘个组合数合并就行了。

时间复杂度 O(nlog2n)

T3

有一个 n 个节点的树,你要从中选出若干条长度为 k 的简单路径(两两边不能相交,点可以相交)。求最大权值和。

n2×105,k=3/4,109wi109

首先肯定往 DP 方面想吧,fx,j (0j<k) 表示节点 x 的子树中,并且从 x 往下选了一条长度为 j 的链,的最大权值。答案就是 f1,0

不过我们发现转移有些棘手,我们分别考虑 k=3k=4

k=3 时,如果 fx,jj=0 我们就是要把 yson(x)fy,0fy,1 两两配对,然后剩下的选 fy,2(当然也可以不选),如果 j>0 就是选一个 yfy,j1 转移上来,剩下同样这么配对。

配对的过程我们可以再搞个 DP,gi,j 表示考虑到第 i 个儿子,当前选的 fy,0fy,2 的差值为 j。记录一下前缀和后缀的 dp 值即可。

k=4 的情况类似,就是 fy,0fy,2 配对,然后 fy,1 之间也要两两配对,剩下的选 fy,3 或不选。给 g 加一维 0/1 表示当先选的 fy,1 的奇偶即可。

不过问题就是,这个 gj 这一维大小是 |son(x)|,这将导致总复杂度变成 O(n2)

但我们真的需要把这一维开到 |son(x)| 吗?

我们把 x 的所有儿子顺序随机打乱,我们发现最优转移的情况就相当于随机一个 +11 的序列,最后的和为 0而这个随机 +1,1 序列的前缀和最大值是低于 O(n)。(这个好像有神仙证了),这意味着我们把 gj 这维开到 O(n) 算出正确答案的概率是及其大的。

于是,时间复杂度 O(nn)

4.9

T1 诈骗题,这不好。

T3 摆烂不看了,反正也没人过(好像数据锅了

T2

计数 n 个点的有向图,满足:

  • 每个点的出度和入度都为 2,且不存在重边
  • 对每个点 u,存在至多一个 pu,不能连边 upu

n500,模 998244353

就大力容斥呗 /cy

题意抽象一下就是,n 对数填到 n 对位置上,其中每个位置有不能填的数,每对位置上的数不能相同,的方案数,不过因为每对位置两个数没有顺序,最终答案要除掉 2n

先容斥掉 pu 不能填的限制,我们先求出一个系数 dpi,j 表示序列中选出了 j 个位置填了对应的 p,且有 j 个位置中有 k 个位置上的数只钦定了一次。记 cnti 表示 i 在序列 p 中出现的次数,容易得到 dp

dpi,j,k=dpi1,j,k+2×cnti×dpi1,j1,k1+4×(cnti2)×dpi1,j2,k

然后,我们设 f(x,y,u,v) 表示 x 个单独的数,y 对数,放入 u 个单独位置,v 对位置的方案。那么最终答案就能写成

ans=j=0n(1)jk=0jdpj,kf(k,2njk2,j,nj)

然后我们考虑求 f,注意此时 fx 个单独位置依然是有限制的,不能填对应的 p,否则填的数就和原来和它一对的位置的数相同了。所以继续容斥

f(x,y,u,v)=i=1x(1)i(xi)g(xi,y,ui,v)

其中 gf 含义类似,只不过单独位置上没有了限制。此时求 g 就容易很多了,若 u>0 考虑枚举其中一个单独位置放了哪个数,有以下递推

g(x,y,u,v)=x×g(x1,y,u1,v)+y×g(x+1,y1,u1,v)

递推边界 u=0,剩下的位置都是成对的,相邻两个位置不能填相同的数,与是继续……容斥。

g(x,y,u,v)=i=0y(1)i(yi)(vi)i!(2(yi)+x)!12yi

然后我们就做完了,发现对于 fg 都有 x+2y=u+2v,所以状态数都是 O(n3) 的,按照上面的式子挨个算,总复杂度 O(n3)

4.11

T1

新听说了一个东西,积和式,不过这个东西没法多项式时间求,好像不是很有用。

不过这个题给的矩阵是一个下海森堡阵,积和式和行列式一样是可以拉普拉斯展开的。所以不断按第一行展开,就容易得到 O(n2) 递推求积和式和行列式的方法。

T2

W(n)=i=1kφ(p1α1pi1αi1)×pi×σ1(pi+1αi+1pkαk),其中 n=i=1kpiαin 的质因数分解。

i=1nW(i)n1010

首先这个数据范围看起来就非常 min25。

但是 W 不是积性函数欸!

再想想,我们有 W(pα×n)=φ(pα)×W(n)+p×σ1(n)n>1n 中不包含质因子 p)。

所以就魔改一下 min25 的第二步求 S 就能做了(要同时筛 Wσ1 的和)

T3

有数列 f0=f1=1,fn=9fn1+12fn2,然后给你 n,P,a,b,c,d,求 gcd(afn+bfn+1,cfn+dfn+1)modPT 组数据。

T105,0a,b,c,d1000,P109+7,n109

首先记 gn=gcd(fn,fn+1),找规律猜出结论,gn=3n/2

然后通过辗转相除将 d 消成 0,现在 ans=gcd(afn+bfn+1,cfn)

先求 G=gcd(afn+bfn+1,fn)=gcd(bfn+1,fn)=gngcd(b,fn/gn)。为了求 gcd(b,fn/gn),我们考虑求 fn/gn 在模 b 下的值,这个是容易矩阵快速幂做的。

现在 ans=G×gcd(afn+bfn+1G,c)=G×gcd(afn/gn+bfn+1/gnG/gn,c)。提出来一个 gn/G 变成 gn×gcd(afn/gn+bfn+1/gn,G/gn×c),跟上一步一样,计算 afn/gn+bfn+1/gnG/gn×c 的值即可。

最终复杂度就是 O(Tlogn)

4.12

T1

T2

维护一个集合 S,支持一下两个操作:

  1. 插入一个数 w

  2. [0,w] 中选择一个数 xS 中选择两个数 i,j,最小化 (i+x)xor(j+x),求这个最小值。

n5×105,w240

首先是经典结论,如果有 a<b<c ,则有 min(axorb,bxorc)axorc。证明考虑 ac 二进制下从高往低第一个不同的位即可。

所以我们发现,能作为答案的 i,j 一定是 S 中元素排序后相邻的数。然后我们再考虑什么样的 x 有可能作为答案,发现 x 作为答案的必要条件是:i+x(或 j+x)是 i(或 j)将二进制下为 0 的一位改成 1,它后面全改成 0 得到的。这样的 x 只有 O(logw) 个,于是能作为答案的 x,i,j 总共只有 O(nlogw) 对。

valix=i 时的最小答案,我们用 set 维护所有可能作为答案的二元组 (x,valx),且 set 中只保留 x1<x2valx1>valx2 的二元组(类似单调栈),这样就可以 O(logn) 的在 set 中二分查询答案了。

复杂度 O(nlognlogw)

T3

码了 8.1 K 的数据结构题,调代码十分心情愉快(斯德哥尔摩了属于是)

一张无向图,最开始图仅有一个 0 号节点。现在有 n 次操作,每次操作为以下 5 种之一(不妨假设每次操作前这张图的节点编号区间为 [l,r]):

  1. 删去 l 号节点,并删去 l 号节点连接的所有边。

  2. 删去 r 号节点,并删去 r 号节点连接的所有边。

  3. 增加 l1 号节点,并连接 min{k1,rl+1} 条边,第 i 条边连接 (l1,l1+i),边有边权。

  4. 增加 r+1 号节点,并连接 min{k1,rl+1} 条边,第 i 条边连接 (r+1,l+1i),边有边权。

  5. 对当前图询问最小生成树的边权和。

n5×105,2k10

动态维护 MST 不是 LCT 吗,有删除?线段树分治好了,我会 O(nklog2n) 暴力!很好,过了

正解的启发思路来源于一个部分分,前 k1 次操作都是 4,此后保证 l0,rk1

我们假设现在已经得到了 [l,r] 的最小生成树,要加入点 l1,此时我们尝试加入边 (l1,l1+i),只需知道 l1l1+i 路径上的最大值即可,也就是说,我们感兴趣的只是 [l,l+k1] 这些点两两路径上的最大值,于是我们把 [l,l+k1] 的点当做关键点,求出其在 [l,r] 最小生成树上的虚树,虚树上的边权为其在原树上代表的路径的边权最大值,该虚树大小只有 O(k),但根据它我们完全可以求出加入 l1 后的最小生成树!

于是我们得到了一下做法,左面加入一个点时,只维护此时 [l,l+k1][0,k1] 在最小生成树上构成的虚树(加上 [0,k1] 是为了方便最后与右边的结果合并),考虑到有删除操作,把过程中得到的虚树全部用 O(nk) 的空间存下来即可。具体地,加入一个点以及其连接的 k1 条边时,与原来的虚树上的所有边放到一起 kruskal 求出新的最小生成树,让后 dfs 求出新的虚树,这部分复杂度为 O(klogk)。右边的同理,询问时,只需把 [l,l+k1][0,k1] 的虚树和 [0,k1][rk+1,r] 的虚树放到一起跑 kruskal 即可,这样总复杂 O(nklogk),我们就做完了这个部分分。

再考虑正解,我们发现其与正解的差别就是正解需要考虑到当前 [l,r] 长度可能小于 k,且 [l,r] 一直在变化不会一直包含 [0,k1],这个的解决方法却非常暴力,那就是定期重构。

设当前 [L,R] (LR+1=k) 为当前的中心区间,如果 r<Rl>L,我们就直接令 [L,R] 变成当前 [l,r] 的中间位置,然后重新计算加入 [l,L1][R+1,r] 点的那些虚树。下面分析复杂度。

考虑势能分析,定义势能 ϕ=max{Ll,rR},插入操作回让 ϕ+1,而重构操作会令 ϕ 减半,重构的复杂度为 O(ϕklogk),那么总的复杂度不会超过 O(nklogk)

还有就是如果当前 rl+1<k 我们就直接 prim 暴力求解即可,复杂度是 O(k2),所以最终的复杂度为 O(nk2)。不过实际的运行时间瓶颈显然不在这里,而在常数巨大的每次构建虚树。


后半个月

posted @   iMya_nlgau  阅读(114)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
点击右上角即可分享
微信分享提示