转眼就到了2020的下半年了…前方仍是一片茫然。
2020.07.02-2020.07.04
Problem | Finished |
---|---|
P2624 [HNOI2008]明明的烦恼 | = = = |
CF156D Clues | √ √ √ |
CF1109D Sasha and Interesting Fact from Graph Theory | √ √ √ |
P5219 无聊的水题 I | √ √ √ |
AT3617 Unicyclic Graph Counting | √ √ √ |
P5206 [WC2019] 数树 | - |
Problem | Finished |
---|
2020.06.29-2020.07.05
At end of time.
星期三总是最恐怖的一天,因为有化学考试…
想法挺简单的,就是代码难写…
对于同一个图的若干个最小生成树有一个很重要的结论,在kruskal算法每次加入完所有相等的边后,这个图的所有最小生成树的连通块组成相同。
因此我们只需要每次加完相同的边,显然每个连通块现在必须完全连通,我们在每个连通块内都做一次矩阵树定理,然后将这个连通块缩成一个点(保证计数不重复)。
答案显然就是这些行列式值的乘积。
复杂度均摊下来是 O ( n 3 ) O(n^3) O(n3)的。
提交记录
sb prufer序列计数题,就是一个广义组合数。
记 s u m = ∑ d i ≠ − 1 d i , D = ∑ d i ≠ − 1 1 sum=\sum_{d_i≠-1} d_i,D=\sum _{d_i≠-1} 1 sum=∑di=−1di,D=∑di=−11
答案 ( n − 2 ) ! ( n − 2 − s u m ) ! ∏ i = 1 D ( d i − 1 ) ! ( n − D ) n − 2 − s u m \frac{(n-2)!}{(n-2-sum)!\prod^D_{i=1}(d_i-1)!}(n-D)^{n-2-sum} (n−2−sum)!∏i=1D(di−1)!(n−2)!(n−D)n−2−sum。
然而这题最大的亮点在于高精度…
提交记录
省选联考套路垃圾题。
提交记录
省选联考题的加强版。
提交记录
答案显然是 n n − 1 n^{n-1} nn−1。
名字和题目描述疑似开车是这题最大的亮点。
答案显然是 ( n − 1 ) ! n n − 2 (n-1)!n^{n-2} (n−1)!nn−2。
注意到答案可以写成 ∑ T s u m ∏ i = 1 k s i z i d e g i \sum_{T}sum\prod^{k}_{i=1}siz_i^{deg_i} ∑Tsum∏i=1ksizidegi( s i z i siz_i sizi为连通块大小, d e g i deg_i degi为连通块缩成点之后的树 T T T对应该点的度数)。
又prufer序列性质可知,每个数在prufer中出现的次数加一即为 d e g deg deg。
那么我们可以发现每棵树答案必定会包含因子 ∏ i = 1 k s i z i \prod^k_{i=1} siz_i ∏i=1ksizi,加下来会随意选 k − 2 k-2 k−2个数放进prufer序列中。
翻译成数学语言就是:
( s i z 1 + s i z 2 + . . . + s i z k ) k − 2 ∏ i = 1 k s i z i = n k − 2 ∏ i = 1 k s i z i (siz_1+siz_2+...+siz_k)^{k-2}\prod^k_{i=1} siz_i=n^{k-2}\prod^k_{i=1} siz_i (siz1+siz2+...+sizk)k−2∏i=1ksizi=nk−2∏i=1ksizi
提交记录
考虑先构造出这个路径,再在在这条路径上连上无关的点。
设在这条路径为 P P P,我们枚举 ∣ P ∣ |P| ∣P∣,我们先再选 ∣ P ∣ − 2 |P|-2 ∣P∣−2个点放在路径上并确定排列顺序,路径上的权值显然可以用插板法分配( ( ∣ P ∣ m − 1 ) \binom{|P|}{m-1} (m−1∣P∣))。
然后考虑将剩下的点连上去,其实只有第一个连上去的点序号必须是路径上的点中的一个,其他的点的序号是可以随意的,即 ∣ P ∣ × n n − ∣ P ∣ − 1 |P|\times n^{n-|P|-1} ∣P∣×nn−∣P∣−1。
提交记录
一开始看这道题以为是容斥题,后来发现我蠢了…
容斥只有在钦定了一些容量必选的时候才需要用到。
对于普通的 = k =k =k到 ≤ k \leq k ≤k完全没必要用到容斥。
显然我们需要求每个点在prufer中出现次数均小于等于 m − 1 m-1 m−1的方案数。
显然可以设计背包dp:
d p i , j = ∑ k = 1 m − 1 ( j k ) d p i − 1 , j − k dp_{i,j}=\sum^{m-1}_{k=1}\binom{j}{k}dp_{i-1,j-k} dpi,j=k=1∑m−1(kj)dpi−1,j−k
因此我们得到了一个 O ( n 2 ) O(n^2) O(n2)的做法。
这个dp显然可以用多项式优化。
先拆组合数:
d p i , j j ! = ∑ k = 0 m − 1 d p i − 1 , j − k ( j − k ) ! × 1 k ! \frac{dp_{i,j}}{j!}=\sum^{m-1}_{k=0}\frac{dp_{i-1,j-k}}{(j-k)!}\times \frac{1}{k!} j!dpi,j=k=0∑m−1(j−k)!dpi−1,j−k×k!1
设 F ( x ) = ∑ k = 0 m − 1 1 k ! x k F(x)=\sum^{m-1}_{k=0}\frac{1}{k!} x^k F(x)=∑k=0m−1k!1xk,可得:
d p n , n − 2 = F ( x ) n [ x n − 2 ] × ( n − 2 ) ! dp_{n,n-2}=F(x)^n[x^{n-2}]\times (n-2)! dpn,n−2=F(x)n[xn−2]×(n−2)!
O ( n log 2 n ) / O ( n log n ) O(n\log^2 n)/O(n\log n) O(nlog2n)/O(nlogn)多项式快速幂均可。
实现的时候被多项式取模坑了好久。
多项式取模的正确方式:一开始长度至少扩展成两个多项式最高次的和,矩阵乘法做完之后再进行取模操作。
提交记录
NOI Online 入门组的题好难啊…做了好久…居然还卡常数…
建议回幼儿园重学
直接记忆化BFS即可…守卫的监察范围显然可以用 O ( n 3 ) O(n^3) O(n3)差分解决。
然而该死的洛谷数据某个点卡时间,最后开着O2卡卡卡终于卡过…
提交记录
sb计数题做了半个小时…我真的是个人才…
提交记录
首先考虑一个 O ( n 2 k ) O(n^2k) O(n2k)的dp。
d p [ u ] [ k ] = min { d p [ v ] [ k − 1 ] + w [ v ] [ u ] } dp[u][k]=\min\{ dp[v][k-1]+w[v][u] \} dp[u][k]=min{dp[v][k−1]+w[v][u]}。
其中 w [ v ] [ u ] w[v][u] w[v][u]表示 u − v u-v u−v之间用一次魔法能得到的最小距离,我们可以用Floyd+ O ( m n 2 ) O(mn^2) O(mn2)预处理得到。
注意到题目中 k k k比较大且每次转移相同,因此我们考虑矩阵快速幂。
那么初始矩阵即为Floyd得到的 d i s t dist dist矩阵,定义这个矩阵间的乘法就为两个矩阵做Floyd,那么答案矩阵就是: d i s t ∗ w k dist*w^k dist∗wk的 ( 1 , n ) (1,n) (1,n)项。
复杂度 O ( n 3 log k + m n 2 ) O(n^3\log k+mn^2) O(n3logk+mn2)。
我们改变 w [ v ] [ u ] w[v][u] w[v][u]的定义可以做到 O ( n 3 log k ) O(n^3\log k) O(n3logk)。
tip:其实矩阵可合并性用图论的观点去理解要容易的多。
提交记录
这题的根号分治做法挺好的。
首先这题就是一个裸的整数划分,根据我们之前学习的知识,我们知道两种做法:
注意到一个方法与插入数字种类数有关系,一个方法与划分个数有关系,根据一些根号分值相关的结论,很容易想到用根号分治将它们结合起来。
最后合并背包即可,复杂度 O ( n n ) O(n\sqrt{n}) O(nn)。
提交记录
不想写题解了怎么办?
搬大佬的博客
提交记录
有些无聊的一道拼凑出来的题。
首先我们先把原图能构成树的方案数求出来。
接下来考虑如何安排取这些边的顺序,显然可以dp。
设 f i , j f_{i,j} fi,j为现在操作 i i i次,加入了 j j j条边的方案数。
我们有 f i , j = j × f i − 1 , j + ( n − j ) × f i − 1 , j − 1 f_{i,j}=j\times f_{i-1,j}+(n-j)\times f_{i-1,j-1} fi,j=j×fi−1,j+(n−j)×fi−1,j−1。
q q q比较大,需要矩阵快速幂解决。
复杂度: O ( n 3 log q ) O(n^3\log q) O(n3logq)。
提交记录
注意到生成树的种类数只由great点的个数决定,因此我们可以拆成两个问题。
定义 m m m为good点个数, g i g_i gi为恰好有 i i i个great点的树的个数, h i h_i hi为选 i i i个点使得其权值之和小于 m a x v a l maxval maxval的方案数。答案就是 ∑ i = 0 m g i × h i \sum^{m}_{i=0}g_i\times h_i ∑i=0mgi×hi。
先考虑计算 h i h_i hi,注意到 n ≤ 40 n\leq 40 n≤40,考虑用双向搜索的方法解决。合并的话我们可以利用单调性用双指针合并双搜得到的两个’物品’。
然后计算 g i g_i gi,考虑容斥。定义 f i f_i fi为great点的个数至多是 i i i个的方案数,这显然是一个二项式反演的形式:
g i = ∑ j = 0 i ( − 1 ) i − j ( i j ) f j g_i=\sum^{i}_{j=0}(-1)^{i-j}\binom{i}{j}f_j gi=j=0∑i(−1)i−j(ji)fj
计算 f i f_i fi很简单,我们只需要在完全图上去掉 [ 1 , i ] [1,i] [1,i]连向 [ i + 1 , m ] [i+1,m] [i+1,m]的边跑Matrix tree即可。
复杂度: O ( n 4 + 2 n 2 n ) O(n^4+2^{\frac{n}{2}}n) O(n4+22nn)。
提交记录
考虑组合意义得到一个 O ( n 4 ) O(n^4) O(n4)dp,发现前两维和后两维和相等于是就是 O ( n 3 ) O(n^3) O(n3)的了。
洛谷评测机越来越慢了…
提交记录
没想出来…又失智了…
很容易设计出来一个有关值域的dp,然而这种做法一不优化一分都拿不到…
显然我们需要离散化,离散化过后值域变成了一整块(所有区间的两个端点排序,相邻的两个点组成一整块)。
考虑在没有任何条件限制下的一整块下如何安排人数,设块长为 L L L,人数为 x x x,那么方案数就为 ( x L ) \binom{x}{L} (Lx)。
意思是我们只需要知道某一块上安排了多少个人就可以知道在这块上安排的方案数。
那么我们设计 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示已经确定了前 i i i个学校,其中在第 j j j块已经安排了 k k k个学校人数在这个范围内。
转移很简单:
f [ i ] [ j ] [ k ] + = ( k l e n j ) ∑ a = 0 j − 1 ∑ b = 0 i − 1 f [ i − 1 ] [ a ] [ b ] ( k = 1 ) f[i][j][k]+=\binom{k}{len_j} \sum^{j-1}_{a=0} \sum^{i-1}_{b=0} f[i-1][a][b](k=1) f[i][j][k]+=(lenjk)a=0∑j−1b=0∑i−1f[i−1][a][b](k=1)
f [ i ] [ j ] [ k ] + = ( k l e n j ) ( k − 1 l e n j ) f [ i − 1 ] [ j ] [ k − 1 ] ( k > 1 ) f[i][j][k]+=\frac{\binom{k}{len_j}}{\binom{k-1}{len_j}}f[i-1][j][k-1](k>1) f[i][j][k]+=(lenjk−1)(lenjk)f[i−1][j][k−1](k>1)
复杂度: O ( n 3 ) O(n^3) O(n3)。
实现上要注意:第一维需要滚动掉,第一个方程中 b b b的上界可以缩小一些否则你谷过不了…
提交记录
2020.07.06-2020.07.12
要期末了啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊。
今天终于不数数了xd…
早说先自己想一想的…结果先看了题解…
首先对于subtask1:我们从 [ 0 , I N F ] [0,INF] [0,INF]开始询问,得到 A 1 , A n A_1,A_n A1,An,然后再查 [ A 1 + 1 , A n − 1 ] [A_1+1,A_n-1] [A1+1,An−1],得到 A 2 , A n − 1 A_2,A_{n-1} A2,An−1,以此类推。
这样做刚好能在 n + 1 2 \frac{n+1}{2} 2n+1次询问之内完成。
subtask2比较巧妙:
这个子任务要求我们询问的长度尽量的小。
首先我们还是先得到 A 1 , A n A_1,A_n A1,An。
有一个显然的性质是区间长度小于 ⌈ A n − A 1 n − 1 ⌉ \lceil \frac{A_n-A_1}{n-1}\rceil ⌈n−1An−A1⌉的一段是不会出现答案的,这样我们可以将区间 [ A 1 , A n ] [A_1,A_n] [A1,An]划分成 ≤ n \leq n ≤n段,那么我们对于每一段询问一次,我们只需要在段与段之间的差值中去最大即可。
这样做的代价是 ( n + 1 ) + ( n − 2 + n ) = 3 n − 1 (n+1)+(n-2+n)=3n-1 (n+1)+(n−2+n)=3n−1,恰好可以通过。
提交记录
矩阵乘法模板题。
提交记录
注意到特殊位置只会修改 O ( m ) O(m) O(m)级别的矩阵,其它的矩阵都是连续的一段区间。
没有修改的循环节我们可以直接矩阵快速幂。
有修改的循环节中没有被修改的段的个数也是 O ( m ) O(m) O(m)级别的,用一个线段树维护这个段中矩阵的乘积即可。
然后这题就成了码农题。
提交记录
其实把那篇很长很长的论文看完就会发现其实和tarjan缩点算法是差不多的…
代码实现太抽象了,看了一下午才看懂…
提交记录
DAG支配树模板题,利用定义找支配当前点的所有点在支配树上的LCA即为该点的父亲。
提交记录
建出最短路径图,可以证明这是一个DAG。
然后建出支配树然后取连通块内非 s s s点中最大的树siz即可。
提交记录
第一次了解支配树就是因为这题。
本来打算学结果看了半天博客没看懂。(感觉论文还好懂些…)
这题我们只需要了解了’支配’的含义就可以了。
首先我们需要一个源点,注意到监控中心没有出度做这个特殊性质,我们可以取原图的反边,然后用一个源点连向所有的监控中心点。
在这个DAG上做一次支配树,显然对于一个点 a a a有且只有支配树上它到根的路径上的点会使其无法到达监控中心,即 d e p [ a ] dep[a] dep[a]。对于两个点显然就是 d e p [ a ] + d e p [ b ] − d e p [ L C A ( a , b ) ] dep[a]+dep[b]-dep[LCA(a,b)] dep[a]+dep[b]−dep[LCA(a,b)]。
提交记录
提交记录
没想到这几天又开始数数了…
因为推导太长了写了一篇学习笔记:
[学习笔记]多项式与有标号无向图计数
不知道为什么,我学OI的热情一下子就被多项式给浇灭了(雾)。
复习AC自动机。
复习拉格朗日插值。
题解见总blog
仔细观察题面发现就是求一个二分图的生成树个数。
然后我们利用prufer序列和Matrix来解出答案是 ( n − k ) k − 1 k n − k − 1 (n−k)^{k−1}k^{n−k−1} (n−k)k−1kn−k−1。
2020.07.13-2020.07.19
暂停一周,准备期末考试。
2020.07.20-2020.07.26
暑假开始了
暑假第一天,先放慢一下速度。
求是否存在 T T T使得其与 S S S的 s a sa sa数组相同且 T T T字典序小于 S S S。
比较显然的一道结论题。
看完题目很容易猜到如果有解则一定存在一个解 T T T使得它与 S S S之间相差一个字符。
然而直接猜结论是一件很冒险的事情,我们需要大致证明一下。
证明:
首先显然 s a sa sa相同的字符串它们的 r a n k rank rank也相同。
考虑 S S S与 T T T的 s a sa sa不相同时,一定存在一个关键数对 ( i , j ) ( i ≠ j ) (i,j)(i≠j) (i,j)(i=j)使得在 S S S中 r a n k i < r a n k j rank_iranki<rankj ,在 T T T中 r a n k i > r a n k j rank_i>rank_j ranki>rankj。
如果 t i ≠ t j t_i≠t_j ti=tj,如果要改变这个顺序我们只需要修改 t i t_i ti或 t j t_j tj中的任意一个字符即可。
如果 t i = t j t_i=t_j ti=tj,依据字典序的比较方式,我们可以得到 ( i + 1 , j + 1 ) (i+1,j+1) (i+1,j+1)也是一个关键数对,以此类推得到 ( i + k , j + k ) [ k = 1 … p , t i + p − 1 = t j + p − 1 ] (i+k,j+k)[k=1\dots p,t_{i+p-1}=t_{j+p-1}] (i+k,j+k)[k=1…p,ti+p−1=tj+p−1]都是关键数对,由于 ( i , j ) (i,j) (i,j)是关键数对,那么 ( i + k , j + k ) (i+k,j+k) (i+k,j+k)中一定有一个关键数对满足 t i + k ≠ t j + k t_{i+k}≠t_{j+k} ti+k=tj+k,即最后一个。
综上我们证明了出现关键数对只需要修改包含一个能够使某个 t i ≠ t j t_i≠t_j ti=tj的位置,得证。
提交记录
期末考试惊现作业题可还行…
原题:LOJ 6072「2017 山东一轮集训 Day5」苹果树
提交记录
原题:「from CommonAnts」一道数学题 加强版
如果不是考到了我才不敢碰这种神仙题目…
考场上整整坑了我三个小时。
题解在这篇学习笔记的最后一个例题中。
无聊的逆序对题,原题可以转化为两个序列通过交换达到各自目标状态的交换步数。
因此判断一下两序列是否同构然后输出逆序对数即可。
提交记录
用线段树维护区间最小值求出差值,然后再求区间hash值即可。
代码不想写。
提交记录
2020.07.27-2020.08.03
由于某些原因,上周的做题记录被咕掉了。
[现在文章长了写起来一卡一卡的,很多内容都尽量转到别的地方去了…]
写出dp转移方程,由于题目要询问区间,因此我们将dp写成矩阵的形式然后用线段树维护。
这题当然也可以支持修改。
一定要注意矩阵乘法的运算顺序问题,这需要依据你的dp顺序而定。
动态DP的本质就是利用矩阵和线段树实现快速修改求答案。
但是在树上,一个点关系到了若干的它的儿子,不是一个完美的区间关系。
于是我们运用树链剖分,每个点选出一个重儿子,对于重儿子的修改,我们也像之前一样的方式用线段树维护,其他儿子的暴力修改。
具体来说我们定义:
g x , 0 = ∑ v ∈ s o n x 且 v ≠ h v s x max { f v , 0 , f v , 1 } g_{x,0}=\sum_{v\in son_x且v≠hvs_x}\max\{ f_{v,0},f_{v,1}\} gx,0=∑v∈sonx且v=hvsxmax{fv,0,fv,1}
g x , 1 = v a l x + ∑ v ∈ s o n x 且 v ≠ h v s x f v , 0 g_{x,1}=val_x+\sum_{v\in son_x且v≠hvs_x}f_{v,0} gx,1=valx+∑v∈sonx且v=hvsxfv,0
那么现在的转移式子为:
f x , 0 = g x , 0 + max { f h v s x , 0 , f h v s x , 1 } f_{x,0}=g_{x,0}+\max\{ f_{hvs_x,0},f_{hvs_x,1}\} fx,0=gx,0+max{fhvsx,0,fhvsx,1}
f x , 1 = g x , 1 + f h v s x , 0 f_{x,1}=g_{x,1}+f_{hvs_x,0} fx,1=gx,1+fhvsx,0
写成矩阵形式之后,我们发现一次修改变的 g g g是 O ( log ) O(\log) O(log)级别的,那么我们暴力修改这些 g g g,其余的我们可以用线段树快速维护。
时间复杂度 O ( n log 2 n ) O(n\log^2 n) O(nlog2n)
跟上面那题差不多,只是式子变了。
CSP原题重做
说是动态DP的题目,但是本题没有修改,可以用相对基础的倍增来解决这个问题。
具体来说我们知道修改两个点只会影响到它们之间的路径与其LCA到根的这一段路径,因此我们考虑定义 w [ x ] [ k ] [ 0 / 1 ] [ 0 / 1 ] w[x][k][0/1][0/1] w[x][k][0/1][0/1]表示强制 x x x和 f a [ x ] [ k ] fa[x][k] fa[x][k]选或者不选的dp值最大和。
然后大概就可以做了。
这题细节特别多,例如在倍增过程中为我们需要处理这条链周围dp值的和,在LCA处我们需要特殊处理周围一圈的dp值的和,倍增过程分为 u − > L C A , v − > L C A , L C A − > 1 u->LCA,v->LCA,LCA->1 u−>LCA,v−>LCA,LCA−>1三段处理。
link
跟GSS3差不多,只是放在了树上,还带修改。
因此我们上树链剖分即可。
然而放在了树上之后我们同样需要考虑矩阵合并的顺序等等各种烦人的东西…
例如我们在线段树上需要分别维护从左到右乘和从右到左乘的乘积,同时我们还需要维护一个lazy tag记录修改情况。
其实是一道比较复杂的题目。
显然我们需要状压dp。
定义 d p [ x ] [ S ] dp[x][S] dp[x][S]为根为 x x x的树包含点集为 S S S的合法树的形态数。
那么我们每次从 S S S中去掉一个 x x x的某一个儿子的子树即可。
d p [ x ] [ S ] = d p [ x ] [ S − S 0 ] × d p [ v ] [ S 0 ] ( x ∉ S 0 ) dp[x][S]=dp[x][S-S_0]\times dp[v][S_0](x\notin S_0) dp[x][S]=dp[x][S−S0]×dp[v][S0](x∈/S0)
然而这样做会使得儿子与儿子之间有顺序,我们需要强制 S 0 S_0 S0包含某一个点来保证不会计算重复。
显然我们需要判断这一种集合划分是否合法。
这要求我们把原题的限制转为等价的充要条件(转载一下AutumnKite
q大佬的wq):
- 对于 L C A \mathrm{LCA} LCA的限制: 1.1. 对于限制 ( a , b , c ) (a,b,c) (a,b,c),如果 c = u c=u c=u,但是 a , b ∈ s u b m a s k a,b\in submask a,b∈submask,那么 L C A \mathrm{LCA} LCA一定不为 c c c,不满足条件。 1.2. 对于限制 ( a , b , c ) (a,b,c) (a,b,c), 如果 c ∈ s u b m a s k c\in submask c∈submask,但 a , b a,b a,b中有至少一个不 s u b m a s k submask submask中,则 L C A \mathrm{LCA} LCA一定不为 c c c,不满足条件。
- 对于边的限制: 2.1. 对于边 ( x , y ) (x,y) (x,y),如果 x , y ≠ u x,y\ne u x,y=u,但是 x , y x,y x,y其中一个在 s u b m a s k submask submask中,另一个不在,则这条边不可能在树上,不满足条件。 2.2. 如果 u u u与 i i i有边且 i ∈ s u b m a s k i\in submask i∈submask的 i i i的数量大于 1 1 1,则不可能有满足条件的树,不满足条件。
至于为什么这是充要条件…如果你知道这样可以做当然就很显然了…
[学习笔记]图论提高题目选做
简单处理一下环即可。
这样的人生没有意义.jpg
求出最小生成树之后用破圈法加边即可,由于加边操作很少,因此如果树边更换则重新处理倍增即可。
破圈法可以直接使用倍增找LCA。
当然如果加边操作多的话就只能LCT了。
我们当然是要计算每个合法括号对对每个链的贡献。
其实直接用dsu on tree维护 f i , g i f_i,g_i fi,gi表示从父亲到儿子方向和从儿子到父亲方向不存在深度小于 0 0 0且现在左括号/右括号失配 i i i个的路径的起点 s i z v siz_v sizv的和即可。
套用dsu的套路我们重链的 f i f_i fi和 g i g_i gi保留,轻链暴力重新统计,然后在统计过程中计算LCA为 x x x的链的答案之和即可。