转载注明地址:https://www.cnblogs.com/syc233/p/13771723.html
前言
没有前言 其实是咕咕咕了 。
P6835 [Cnoi2020]线形生物
题解
月赛时没做出来的题,下来看了题解才会。
令从 \(x\) 走到 \(y\) 的期望步数为 \(E_{x\to y}\) ,\(x\) 的返祖边集合为 \(S_x\) ,\(S_x\) 的大小为 \(deg_x\) ,则:
\[\begin{aligned} E_{x\to x+1}&=\frac{1}{deg_x+1}\times 1+\frac{1}{deg_x+1}\sum_{(x,y)\in S_x}(E_{y\to x+1}+1)\\ &=1+\frac{1}{deg_x+1}\sum_{(x,y)\in S_x}\sum_{i=y}^xE_{i\to i+1}\\ \end{aligned} \]令 \(sum_x=\sum_{i=1}^xE_{i\to i+1}\) ,则:
\[\begin{aligned} E_{x\to x+1}&=1+\frac{1}{deg_x+1}\sum_{(x,y)\in S_x}(sum_x-sum_{y-1})\\ &=1+\frac{1}{deg_x+1}\sum_{(x,y)\in S_x}(sum_{x-1}-sum_{y-1})+E_{x\to x+1}\\ \end{aligned} \]为了让 \(E_{x\to x+1}\) 能通过递推求出,将等式右边与 \(E_{x\to x+1}\) 有关的项移到左边去,并且消去分母:
\[\begin{aligned} E_{x\to x+1}&=1+deg_x+\sum_{(x,y)\in S_x}(sum_{x-1}-sum_{y-1})\\ \end{aligned} \]然后记录个前缀和就好了。
P3899 [湖南集训]谈笑风生
题解
对 \(b\) 的位置分类讨论:
- 若 \(b\) 在 \(a\) 上方,这种情况对答案的贡献为 \(min(dep_a-1,k)\times (size_a-1)\) 。
- 若 \(b\) 在 \(a\) 下方,则答案为 \(a\) 的子树中与 \(a\) 相距不超过 \(k\) 的结点的子树大小减一的和,线段树合并即可。
P5384 [Cnoi2019]雪松果树
题解
求 \(k-cousin\) 个数可以转化为求 \(k-father\) 的 \(k-son\) 个数。
将询问离线,线段树合并即可。
用到一堆奇技淫巧可以让线段树合并的空间复杂度降到 \(O(n)\) 。
P2050 [NOI2012]美食节
题解
P2053 [SCOI2007]修车 的加强版。
直接连一个完全二分图显然边数爆炸,所以得动态加点。
若一个厨师在上一轮增广中做了菜,那么给这个厨师新增一个结点。
这样能避免添加很多无用结点,总结点数与总人数同阶。
CF280D k-Maximum Subsequence Sum
题解
贪心思想,选取不超过 \(k\) 段不相交的子段使子段和最大,那么一定在子段和最大到前 \(k\) 大的子段中选。
模拟费用流。
对于所有 \(i\in[1,n]\) ,连边 \(i\to i+1\) ,容量为 \(1\) ,费用为 \(a_i\) 。
建立源点 \(s\) 和汇点 \(t\) 。从 \(s\) 向结点 \(i\in[1,n+1]\) 分别连一条容量为 \(1\) ,费用为 \(0\) 的边;分别从结点 \(i\in[1,n+1]\) 向 \(t\) 连一条容量为 \(1\) ,费用为 \(0\) 的边。这样一单位流经 \(s\to i\to j\to t\) 的流代表选取了区间 \([i,j-1]\) 。
为了使子段和最大,每次跑最大费用流且只推送一单位的容量,直到推送了 \(k\) 个单位的容量,或者费用为负数,停止增广。结合上面的贪心思想可知这样做是对的。
注意到每次跑费用流的过程中,一单位流经 \(s\to i\to j\to t\) 的流会将区间 \([i,j-1]\) 取相反数,那么可以用线段树模拟这个过程。
线段树维护区间最大子段和和子段和最大的子段的左右端点,和区间最小子段和和子段和最小的子段的左右端点用于取相反数的操作。
P4843 清理雪道
题解
有源汇上下界最小流。
每条边都得经过至少一次,且能在任何一个点放下一个人,在任何一个点结束。
连边 \(s\to i,i\in[1,n]\) ,容量上界为 \(+\infin\) ,下界为 \(0\) 。
连边 \(i\to t,i\in[1,n]\) ,容量上界为 \(+\infin\) ,下界为 \(0\) 。
对于原图中的边 \(u\to v\) ,连边 \(u\to v\) ,容量上界为 \(+\infin\) ,下界为 \(1\) 。
跑有源汇上下界最小流。
至于有源汇上下界最小流怎么跑,先不连边 \(t\to s\) ,跑一遍可行流,尽量填充非必须流,在连上 \(t\to s\) 增广,最后边 \(t\to s\) 中的流量即为最小流。
P3119 [USACO15JAN]Grass Cownoisseur G
题解
容易发现,若逆行的边的起点和终点在同一个强连通分量中,则对答案没有影响。
于是先缩点,跑出起点为 \(s\) 所在的强连通分量和终点为 \(s\) 所在的强连通分量的最长路,枚举逆行的边。
CF547E Mike and Friends
题解
将所有字符串插入AC自动机中,建出fail树。
那么问题就转化为:询问 \(s_k\) 在AC自动机上的结束结点的子树中,有多少结点属于 \(s_{l \cdots r}\) (即插入Trie时经过的结点)。
线段树合并即可。
SP1811 LCS - Longest Common Substring
题解
对第一个串建SAM,用类似AC自动机上匹配的方法让第二个串在SAM上匹配。
令当前匹配到的结点编号为 \(u\) ,以 \(u\) 结尾的最长匹配长度为 \(now\) ,初始时 \(u=1,now=0\) 。
设当前加入的字符为 \(c\) ,则:
- 若 \(u\) 有 \(c\) 对应的出边,则 \(u\) 跳到对应出边到达的结点,匹配长度 \(now\) 加一。
- 若 \(u\) 没有 \(c\) 对应的出边,则从 \(u\) 沿着parent树向上跳,直到第一个有 \(c\) 对应出边的结点 \(u'\):
- 若不存在 \(u'\) ,则令 \(u=1,now=0\) ,重新开始匹配。
- 因为 \(u'\) 对应的等价类中的子串一定是 \(u\) 中对应等价类中子串的后缀,所以 \(u'\) 结点处的最长匹配长度即为 \(len(u')\) 。在 \(u'\) 类中的最长串后加入一个字符 \(c\) ,令 \(now=len(u')+1\),\(u\) 跳到 \(u'\) 的 \(c\) 对应出边到达的结点。
每次跳到一个结点时更新最长公共子串长度即可。
SP1812 LCS2 - Longest Common Substring II
题解
上面那题的加强版,依然采用上题的方法。
先对第一个串建SAM,然后让其他串在SAM上匹配。
这道题和上一道的不同之处是,这道题需记录 \(now\) ,即匹配到结点 \(u\) 时的最长匹配长度。令 \(Max_u\) 为当前串在SAM上匹配到结点 \(u\) 时的最长匹配长度。
由parent树的性质,若点 \(u\) 的最长匹配长度为 \(Max_u\) ,则 \(u\) 在parent树上的祖先 \(a\) 的最长匹配长度 \(Max_a=\max(Max_a,\min(Max_u,len(a)))\) 。
每个点 \(u\) 记录一下每个串在 \(u\) 的最长匹配长度的最小值 \(Min_u\) ,则答案即为 \(\max_{u\in SAM}Min_u\) 。
P3975 [TJOI2015]弦论
题解
求一个串字典序第 \(k\) 小的子串。
对这个串建立SAM,每个点处理出它的endpos类的大小 \(size\),这个可以在parent树上统计。每个点的endpos类的大小代表了在SAM上,从源点到这个点构成的子串在原串中的出现次数。
再在SAM上处理出经过每个点的子串个数 \(sum\) 。显然,\(sum_u\) 即为 \(u\) 在SAM上能到达的结点的 \(size\) 大小之和。
求第 \(k\) 大的子串只需要从源点开始匹配即可。
P4094 [HEOI2016/TJOI2016]字符串
题解
二分最长公共前缀长度 \(mid\) ,于是只需要判断 \(s[c\cdots c+mid-1]\) 这个字符串是否是 \(s[a\cdots b]\) 的子串。
对 \(s\) 建立SAM,记录每个点的endpos类(线段树合并),和所有前缀在SAM上对应的结点。
每次找到 \(s[1\cdots c+mid-1]\) 在SAM上的对应结点,在parent树上倍增找到最后一个 \(len\geq mid\) 的祖先 \(u\) ,\(s[c\cdots c+mid-1]\) 即在点 \(u\) 内。若点 \(u\) 的endpos类中存在一个数在 \([a+mid-1,b]\) 内,那么串 \(s[c\cdots c+mid-1]\) 即是 \(s[a\cdots b]\) 的子串,在线段树上查询区间 \([a+mid-1,b]\) 即可。
P3181 [HAOI2016]找相同字符
题解
将两个串塞进广义SAM中,分别处理出两个串在每个点的endpos类大小 \(size_{0,u},size_{1,u}\) ,那么答案即为:
\[\sum_{u\in SAM}size_{0,u}\times size_{1,u}\times(len(u)-len(fa(u))) \]P4081 [USACO17DEC]Standing Out from the Herd P
题解
广义SAM。
插入每个字符串时,\(bl_u\) 记录每个结点属于的串的编号,若属于多个串则 \(bl_u=-1\) 。
因为每个结点的信息可以更新它在parent树上的祖先结点的信息,所以最后跑一下拓扑排序更新祖先信息即可。
最后遍历所有结点,若 \(bl_u\not =-1\) ,那么这个点会对串 \(bl_u\) 的答案产生 \(len(u)-len(fa(u))\) 的贡献。
CF666E Forensic Examination
题解
广义SAM+线段树合并。
对所有 \(T\) 串建立一个广义SAM。在parent树上线段树合并记录区间出现次数最多的串。
查询时在parent树上倍增找到 \(S[p_l\cdots p_r]\) 所属的结点,在线段树上查询区间 \([l,r]\) 的信息即可。
SP8093 JZPGYZ - Sevenk Love Oimaster
题解
因为屑SPOJ不给看错误信息,这题调得我心力交瘁
对所有模板串建立一个广义SAM,每个结点用vector记录它存储的串的信息的编号。
然后将询问离线下来区间数颜色即可。
P2336 [SCOI2012]喵星球上的点名
题解
将每只喵的姓和名用一个特殊字符连接起来,插入到广义SAM中。
问题一就是区间数颜色问题,用莫队和树状数组均可。
问题二是求每种颜色被多少个区间数到了。在跑莫队的时候给每种颜色记录一个存在时间,即最后一个这种颜色的数被弹出区间的时间减去第一个这种颜色的数加入区间的时间,那么每种颜色的答案就是它存在时间之和。
P6257 [ICPC2019 WF]First of Her Name
题解
按输入建出AC自动机,再把询问串插入AC自动机中
只需要求询问串在fail树上对应的结点的子树中有几个结点对应了一个夫人的名字。
建出fail树后dfs统计子树答案即可。
P1453 城市环路
题解
基环树最大独立集。
在树上和环上分别做一次DP即可。
CF123E Maze
题解
考虑每条边的期望经过次数。令 \(S\) 为根,对边 \(e\) 的位置分类讨论:
- 若边 \(e\) 在 \(T\) 的子树内,则期望经过次数为 \(0\) 。
- 否则,令 \(e\) 连接的深度较小的结点为 \(u\) ,\(u\) 和 \(T\) 的LCA为 \(v\) ,那么在 \(v\) 访问子结点时,只有 \(u\) 所在的子树在访问 \(T\) 所在的子树之前被访问到,\(e\) 才会被经过,这样的概率是 \(\frac{1}{2}\) 。则 \(e\) 的期望经过次数为 \(\frac{1}{2}\times 2+\frac{1}{2}\times 0=1\) 。
所以只有 \(T\) 子树之外的边才会对答案产生贡献。
枚举 \(T\) ,分 \(S\) 在 \(T\) 的子树内和 \(S\) 在 \(T\) 的子树外两种情况统计答案。
P3647 [APIO2014]连珠线
题解
换根DP。
先考虑根确定时怎么DP:令 \(f_{u,0/1}\) 表示点 \(u\) 用第一/二种方式插入图中,指定点 \(u\) 的子树中的边的颜色所能得到的最大得分。
分类讨论 \(u\) 与儿子 \(v\) 之间的边的颜色进行转移:
\[\begin{aligned} f_{u,0}&=\sum_{v\in son_u}\max(f_{v,0},f_{v,1}+w(u,v))\\ f_{u,1}&=\max_{v\in son_u}\{f_{u,0}-\max(f_{v,0},f_{v,1}+w(u,v))+f_{v,0}+w(u,v)\}\\ &=f_{u,0}+\max_{v\in son_u}\{f_{v,0}+w(u,v)-\max(f_{v,0},f_{v,1}+w(u,v))\} \end{aligned} \]记录最大值和次大值换根DP即可。
CF1051F The Shortest Statement
题解
好题啊好题。
注意到 \(m-n\leq 20\) ,于是这个图可以看作是一个生成树上加入了 \(m-n+1\leq 21\) 条边。
这样两个点的最短路要么只经过树边,要么会经过非树边。若经过非树边,则一定会经过非树边对应的两个端点,而这样的端点个数不超过 \(2\times(m-n+1)\leq 42\) 个,于是可以以每一个端点为起点跑一遍Dijkstra,求出从每个端点到每个点的最短路。
令树上两点距离为 \(dist(u,v)\),非树边端点所属的集合为 \(S\), 那么答案即为:
\[\min(dist(u,v),\min_{x\in S}\{dis(u,x)+dis(v,x)\}) \]CF1096F Inversion Expectation
题解
令未知数个数为 \(x\) ,将逆序对分为三类:
-
已知数之间的逆序对。用树状数组可以算出。
-
未知数之间的逆序对。随机选两个数,它们能成为一个逆序对的概率为 \(\frac{1}{2}\) ,则一对未知数贡献 \(\frac{1}{2}\) 个逆序对。则这种逆序对数期望有 \(\frac{x\times(x-1)\times\frac{1}{2}}{2}\) 个。
-
未知数与已知数之间的逆序对,考虑每一个已知数 \(p_i\) 与所有未知数构成的逆序对的期望个数:
-
令 \(cntr\) 为未知数可选的数中大于 \(p_i\) 的数的个数,则一个未知数比 \(p_i\) 大的概率为 \(\frac{cntr}{x}\) ,令 \(i\) 之前有 \(y\) 个未知数,则 \(p_i\) 与它前面的未知数构成的逆序对个数期望有 \(y\times \frac{cntr}{x}\) 个。
-
令 \(cntl\) 为未知数可选的数中小于 \(p_i\) 的数的个数,令 \(i\) 之后有 \(z\) 个未知数,同理, \(p_i\) 与它后面的未知数构成的逆序对个数期望有 \(z\times \frac{cntl}{x}\) 个。
\(cntr,cntl,y,z\) 都可以前缀和预处理出来。
-
把三种情况的答案加起来即可。
P3159 [CQOI2012]交换棋子
题解
有次数上限的限制容易想到网络流,但是这个建模难想。
一种显然的建模方式是将相邻格子互相连边,容量为 \(+\infin\) ,费用为 \(1\) ,表示移动棋子。但是这样无法满足次数上限限制。
于是想到将每个点拆成入点和出点,分别连接入点和出点,入点和出点连边表示这个格子最多使用多少次。但是在这道题中移入和移出棋子都会使用这个格子,只拆两个点也无法表示出这道题的限制。
于是就拆成三个点,分别为入点、出点和内部点,连边入点 \(\to\) 内部点 \(\to\) 出点。那么流从内部点流向出点表示棋子移出这个点,流从入点流向内部点表示棋子移入这个点。
那么现在只需要解决如何将次数限制分配到两条内部边上。
若次数限制为偶数,直接均分即可。否则分类讨论:
-
若初始和目标状态这个格子的棋子颜色相同,那么移入这个格子的棋子数应该和移出这个格子的棋子数相同,那么只需要将限制均分到两条边上即可。
-
若初始状态有黑棋而目标状态没有黑棋,那么一定有一个棋子移出,让连接内部点和出点的边的容量多一即可。
-
否则,让连接入点和内部点的边的容量多一。
然后就是费用流模板。
然而这道题有一个坑点:相邻是指有公共边或公共顶点。
P3163 [CQOI2014]危桥
题解
先跑一遍网络流,再交换一对起点和终点再跑一遍,若两次的最大流均为 \(2\times (a_n+b_n)\) ,那么可行。证明。
我是不会证的了/fad
CF1427A Avoiding Zero
题解
令所有正数的和为 \(sum1\) ,所有负数的绝对值的和为 \(sum2\) 。
发现当且仅当 \(sum1=sum2\) 时无解。
当 \(sum1>sum2\) 时,可以将所有正数放在前面,这样所有前缀和都大于 \(0\) 。
否则将所有负数放在前面,所有前缀和都小于 \(0\) 。
LOJ2348 「JOI 2018 Final」美术展览
题解
这题被葛队用不到10min切掉了/fad。
发现若固定 \(A_{min}\) 和 \(A_{max}\) ,那么一定将尺寸在 \([A_{min},A_{max}]\) 中的物品选完,那么 \(S\) 的值就很好求得。将物品按 \(A\) 升序排序,那么选择的物品一定是一段区间。
同时固定两个值有些困难,先固定一个值 \(A_{min}\)。令 \(A_{min}\) 在排好序的物品中下标为 \(i\) , \(A_{max}\) 的下标为 \(j\) ,有 \(i\leq j\) 。则需要最大化的值即为:
\[\sum_{k=i}^jB_k-(A_j-A_i) \]令 \(sum\) 表示 \(B\) 的前缀和,则有:
\[sum_j-sum_{i-1}-(A_j-A_i)=sum_j-A_j-(sum_{i-1}-A_i) \]从右到左枚举 \(i\) ,记录 \(sum_j-A_j,j\in [i,n]\) 的最大值,依次更新答案即可。
P5212 SubString
题解
SAM+LCT毒瘤。
用LCT动态维护parent树,并动态更新endpos类大小。
新加入一个点相当于将它到根上的点的endpos大小加一,LCT链加、单点查询即可。
CF1430E String Reversal
题解
将一个字符串翻转,每次可以交换相邻两个字符,求最少交换次数。
将每个位置赋值为它的目标位置。若没有相同字符,那么答案即为这个序列的逆序对数。
有相同字符的话,让相同字符组成的子序列的目标位置单调递增,即可让逆序对数较小。
待添加