罪的晚风,可曾带回朝露映的清纯?|

LarsWerner

园龄:4年11个月粉丝:20关注:3

卷不起来了

CF19E Fairy

给定无向图 G=(V,E),求所有边 eE 满足 G(V,Ee) 是二分图。

二分图相当于不存在奇环,所以 e 必须属于所有奇环的交集的边。于是我们的目标变成求出所有简单奇环的交。(如果原本就是二分图就直接特判输出结束。)

找到 G 的一棵 dfs 树。任何一个非树边 x 都对应一个简单环。若 x 形成的环是奇环,则我们称它为坏的,否则为好的。

删边分两种情况:非树边和树边。

非树边的情况非常好判,直接看坏的非树边的个数即可。若坏的非树边是唯一的,那么意味着我们可以删除那条非树边;否则任何一条非树边必然不可能成为答案。

现在考虑树边。我们想要知道可删的树边 y 会具有的性质。y 可删当且仅当它在所有环的交上,并且不能形成新的奇环。于是,y 必须在所有坏的非树边的环上(不然无法覆盖环)且 y 不能在任何好的非树边的环上(不然会形成新的奇环)。由于是树上路径问题我们可以直接树上差分一下即可。

注意不连通的情况。

https://codeforces.com/contest/19/submission/144276500

CF22E Scheme

给定内向基环森林 G=(V,E),求最小的新增边集 E0 使得 G(V,EE0) 为强联通图。

将每一棵基环树缩成一棵普通树。将内向树改成强联通的方法只需根往叶节点连边即可。

但是考虑多个连通块的情况需要更加谨慎。把树全部改成强联通图然后再串起来显然是不优的。考虑答案的下界必为 叶节点数量。这个下界是可以达到的:每棵树先根 叶子这样连直到还剩一个叶子结点。然后再用剩余的所有根和叶子结点串起来即可。

由于这题构造的特殊性所以很多代码地方尤为简便,如 DFS 时不需要找到环只需要得到一个环上点等。

https://codeforces.com/contest/22/submission/144298318

CF62F Wormhouse

给定无向图 G 的一条欧拉回路 P。找到另外一条欧拉回路 Q 使得其字典序比 P 大且是所有满足条件的欧拉回路中字典序最小的。

对于每一个点,由于无论先走哪一条出边,最终总是能得到一条欧拉回路。基于这个,我们可以直接贪心搜索,搜的同时记录一下目前字典序是否已经超过,然后将不合法情况剪枝。

这样搜索复杂度极其正确。由于每次必然能搜到,而且每次都可以限制字典序不能小于 P,所以搜时的路径必然是 得到 P  回溯直到存在可行的边 得到 Q,于是乎复杂度非常正确。

https://codeforces.com/contest/62/submission/144405442

一道 模拟赛题

给定无向图 G,对于每个节点 u,令 fu 表示经过 u 的最短的经过至少一个简单环的回路,求出所有 fu2

一个如此的回路必然可以表示成两条 susv(u,v) 组成,并且为了最短,需要有 du,dv 尽可能的短。若要计算出严格的最短路只能用 floyd 解决。但是我们可以从每个点开始 bfs,在松弛的时候判断 u 和其非前驱已经更新过的邻居 v 组成的一个环。这样能保证最先 bfs 到的节点和正确答案最多差 1

CF51F Caterpillar

给定无向图 G,你每次可以合并两个节点(节点合二为一,继承原来的所有边),问最少多少步后可以让图变成一个允许有自环但不允许有重边的毛毛虫。

因为边不会减少,所以对于任意边双联通分量,要缩成毛毛虫最终必然只会缩成一个点,并且需要 s1 步(设大小为 s)。

在确定了这点后,我们很容易想到把它按边双缩点,最终得到一个森林。森林最终必然可以化成几棵树形成的毛毛虫连在一块,所以只需要考虑树如何变成毛毛虫。

叶子结点数量必然大于其父亲层的节点的数量。所以我们选择这些叶子结点作为毛毛虫的足,然后直径作为路径,其他点全部并掉。容易证明这样是最优解。

注意要特判一下缩成的森林中含有一些单点的情况。

https://codeforces.com/contest/51/submission/144852908

CF117C Cycle

给定一个竞赛图 G,从中找出一个有向三元环。n5000

如果普通图只能做到 O(n3w),所以要充分利用竞赛图的性质:竞赛图有环等价于有三元环。对于一个大小为 x>3 的环,总能从中找到连续三点 abc。若存在 ca,则找到三元环;若不存在,则可以将 b 踢出这个环,缩成一个规模为 x1 的问题。所以第一个算法有了:找到任意一个环,然后缩环。

基于这个可以考虑一个更简单的算法。我们不喜欢 abc,ac 的组合。实际上,如果这种组合存在,那么 ac 一定是没有价值的。如果存在 d 满足 cdac,那么 a,b,d 或者 b,c,d 其中一者一定能构成一个三元环。所以遇到这种情况我们直接把 ac 给干掉。在干掉了所有这样的边后,我们一定能得到一个外向基环树,即每个点只有一个出边2。这样我们只需要枚举两点即可。

https://codeforces.com/contest/117/submission/144926390

CF160D

给定一张带权无向图 G=(V,E),对于所有 eE,判断 e 是否一定/可能/不可能出现在 G 的最小生成树上。

双 log 做法:e 可能在 MST 上要求路径上不存在比自己小的边;e 一定在 MST 上要求路径上不存在不超过自己的边。于是先得到一棵 MST 后做树剖分别处理树边和非树边。线段树要求支持区间取 min,然后查询 min 和单点,是非常容易做的。

单 log 做法(瓶颈为排序):首先得到所有 MST 的交集 G=(V,E)。然后我们发现 G 的桥必然是一定会出现在 MST 上的点;否则就是可能出现在 MST 上的边。我们需要在进行 Kruskal 的过程中动态地去缩点找桥。对于每一种边权我们都集体找一次桥然后缩点。为了保证增量式的复杂度,每次缩点只需要把增加的新边两端的 dfn 设为 0 即可。

https://codeforces.com/contest/160/submission/145128623

CF240E Road Repairs

给定一个 01 权图 G,求其最小外向树形图。

这题完全不需要复杂的算法。

考虑一种生成树的方法:从第一个点开始 BFS,然后向外找出边。但是这样并不能得到一个最小树形图。由于这题的特殊 01 权性质,我们发现一旦一个点被 0 权边占领了入度,那么它永远都不需要再更新了。在此基础上,我们进行普通的 BFS,便可以得到一个最小树形图。

这样得到的最小树形图是满足这样的 01 最小树形图的贪心性质的,即不存在任何 0 权边的组合可以替代 1 权边。

https://codeforces.com/contest/240/submission/145268981

CF317C Balance

给定一张图,每个点有一个容量为 v 的容器,并装入了 ai 单位的水。每次操作可以选择两点 u,v 和水量 c,并且将 c 单位的水按照图上的一条边从 u 转移到 v。需要保证中途不会有容器中的水溢出。问是否有在 2n2 步内的方案使每个点的水量变成 bi

对于任意两个点 u,v,我们考虑其运输路径的最大量 c。首先可以从 v 开始考虑,从 v 的前驱中运尽可能多的水给 v,然后再从前驱的前驱运给前驱,不断递归下去,直到 u 给自己的后继运出 c 单位的水。

然后考虑原问题。我们把水分成两组,需要运出去的 A 组和需要运进来的 B 组。由于只需要找到一组可行解,我们尝试每次选择任意两个 sAtB,然后期望从 smin(asbs,btat)t

CF81E Pairs

给定一个黑白基环森林 G,求最大匹配,并在此基础上最大化一黑一白的匹配个数。

首先树是非常好用 DP 求的。

可以考虑环怎么求然后在环上再做一次 DP。但这样太烦了。

注意到不可能存在一种情况使得环上相邻三点 abc 有两个匹配。所以可以直接断边,分断 ab 和断 bc 两种情况即可。


ARC066B Xor Sum

首先 uv 是非常显然的。

fv 表示对于 v 有多少个符合要求的 u

有一个有趣的性质,就是 a2b2=ab2

又因为这个 1018 如果不能 O(1) 算的话应该是个 polylog 状物,所以看能不能从折半后的 f 转移过来。

折半后必然涉及到奇偶不同的问题,于是分奇偶考虑。

如果 v 是奇数,那么 a,b 必定一奇一偶,于是又有 a2+b2=a+b2,所以可以直接转移过来,即 f2v+1=fv

如果 v 是偶数,那么 a,b 可能是全偶可能是全奇数,于是两种情况,其中全奇数的话 a2+b2=a+b21,全偶的话和一奇一偶是一样的,所以有 f2v=fv+fv1

我们要求的答案是 f 的前缀和 s,我们不断拆 f 可以得到

si={sk+2sk1i=2k2sk+sk1i=2k+1

我们发现需要求的 s 的数量在 O(logn),可以通过此题。

ARC066C

最优解一定要么是不加括号要么是加一些括号使得可以表示成 ABC 连接起来的表达式,并且 A 中没有括号,B 中对答案的贡献都是负数,C 中对答案的贡献都是正数,并且原式中 B 两边都是负号,然后就做完了。

ARC066D

挺烦的一道斜率优化题。

首先先不考虑修改,可以用斜率优化直接做。

然后考虑修改的问题。可以处理处前缀答案 fx 和后缀答案 gx,然后我们还要考虑一个 hx 表示 x 必选的全局最优解,也就是说我们要处理处 maxlxrp(l,r),其中 p 是一个有关 f,g 和一堆系数的式子。

然后这个东西可以用一个类似 cdq 分治的东西维护。

考虑左端点对于右端点的贡献,可以把左端点的东西拉出来然后给到右边的右端点做类似斜率优化 DP 的东西。

ARC069B

确定任意两个相邻的元素就能把整个序列定下来。

ARC069C

模拟一下过程就能知道答案怎么求了。对于每一个顶在最前面的前缀最大值,它出现的次数就是后面比它大的个数乘上自己与下一个出现的数字的差。

CF1080E

考虑子矩阵合法的充要条件。

首先,对于每一行,我们需要其出现次数为奇数的字符个数 1。然后考虑每一列。我们需要保证第 i 行和倒数第 j 行的字符集是相等的,这样才能保证可以构成回文的列。

我们枚举最终子矩阵的左右端点,这样就能判断每一行是否合法。对于合法的连续子段,我们就可以直接做 Manacher。

复杂度 O(mn2)

卡常,一生之敌。

https://codeforces.com/contest/1080/submission/149824444

THUPC2018 绿绿和串串

最后一次操作前的串的结尾必须满足 i+pin,其中 pi 为回文半径。

然后每往前一步,只需要找其中点的回文半径是否可行即可。就能得到所有可行串。

UVALive6071

vjudge.net/problem/UVALive-6071

这东西和树同构有关。我们先求出每个子树的哈希值。

对于相同的子树,他们在重排的意义下同构,于是我们可以用组合数来解决这些之间的计数。

对于环,可以直接上 burnside。

BJOI2019 奥术神杖

几何平均值->取对数变成算数平均值,然后分数规划。

ans=vi|S|=exp(1|S|lnvi)

分数规划,二分答案为 d,则有每个(选中词)的价值为 lnvid

然后再 AC 自动机上 DP,f(i,j) 表示前 i 个并且在自动机上在点 j 上的最大收益。

然后就是还要输出方案(令人窒息...)。

HEOI2016 字符串

相当于给定 l,r,x,在 [l,r] 中找 y 使得 lcp(x,y) 最大。

二分答案 d,则 lcpd 的形成一段区间,可以两侧二分求出区间。然后判断区间前缀是否有位置落在 [l,r] 中。把位置和 rank 看成两个维度,这就是二维数点问题。

修改的代价为长度减去 lcp,所以可以转换成两两匹配使得 lcp 之和最大。以 x 和 y 开头的两个串的 lcp 即两个后缀的 lcp 与 k 取 min。

两个串接起来建 SAM,则两个后缀的 lcp 就是两个对应节点在后缀树上的 lca 深度。

做一个树上贪心匹配即可。

CF700E

考虑后缀树上深度最大的节点,一定是叶子结点。

后缀树有一个易证性质:同一节点所代表的串(无论长短)在其子嗣节点中出现次数都是一样的,出现位置都为 right 集合且不会卡出去。

考虑 DP。f(i) 表示从更节点到 i 最多能选多少个点,转移为 fi=max(ffai,maxj在i中出现至少2次fj+1)

对于 fj<ffai,则就不需要考虑 j。所以我们只需要考虑 fj=ffai 转移。维护 fj=ffai 的最浅的 j,判断是否出现两次即可。判断的话需要用线段树合并维护 right 集合。

CF GYM 103409 J

考虑一个节点有长度为 [l,r] 的串,于是这个点对 [l,r] 区间有贡献。然后我们就可以知道长度为 x 的点有多少个。这样询问转化成了固定长度求第 k 个。

考虑对于所有长度离线处理,并对此扫描线。所以现在我们需简要维护插入/删除左端点和同一点内查询第 K 个。

???

给定字符串 s 和正整数 k,将 s 划分成 k 段可空段,使得 k 段字典序最大值最小。

假设 S 的 lyndon 分解为 s1p1s2p2,那么如果 kp1,就均分 p1 的段;否则尽可能给 p1 的段多一点,然后再往后分。

CF843D Dynamic Shortest Path

首先肯定地,需要跑一遍普通地 Dijkstra。

每次改变后,得到的 di 只增不减。所以松弛影响最短路的增量。考虑增量对其影响。射 e(x,y)=dx+e(x,y)dy,对所有 e 做 dijkstra。由于最短路增量一定 <n,故用桶维护即可达到可过的复杂度。

实现 10s 的题有 200 个 testcase... 很不合理

https://codeforces.com/contest/843/submission/150624878

CF653G Move by Prime

首先各个质因子之间互不影响。考虑对质因子 p 的修改:设 aip 的从次数为 qi,则最终所有 q 都要变成现在的 q 的中位数 x,也就是说其对答案的贡献为 |xqi|。这个中位数看上去很难处理,实际上是抵消掉的,我们只需要考虑 qi 的贡献的正负性。

这种子序列的题可以考虑对于每一个元素算贡献。设 q 排名为 i 的数,小于它的选了 a 个,大于的选了 b 个。我们枚举左边不选的数加上右边选了的数 z=i1a+b,则有贡献

cy=qi×(j=in1(n1j)+j=0i2(n1j))

枚举质数 pi,然后找到所有 a 中出现的倍数,然后组合数用前缀和即可,复杂度 O(nlogn)

注意到对于指定的 qi,后面这段必然是一段连续和。于是再对这个做一次前缀和即可。(做不做在效率上区别不大)。

https://codeforces.com/contest/653/submission/150686779

CF512D Fox And Travelling

首先环肯定碰不到,用拓扑排序把环全部删去,得到一个森林。森林中有两种树,一种为可以从任意叶子结点出发的枣树,一种为有一个点 r 不能从其出发的枣树。先考虑第二种。我们将 r 作为根,所求相当于该树的所有符合要求的长 k 的序列数量。这个和有向树的拓扑序很像。考虑 DP。f(u,i) 表示 u 子树中长 i 的序列数量。和求树的拓扑序的转移类似,我们套上一个树上背包,有

f(u,x)=aj=x(xk<jakaj)f(vj,aj)

其实按照普通 DP 的转移,相当于 f(u,x+y)=(x+yx)f(u,x)f(v,y)

对于第一种无根树,我们强行钦定每个节点都做一次根,这样对于选 k 个点的方案就被统计了 sk 次,其中 s 为树的大小。

我们得到了这些树的结果后,再把他们暴力卷起来即可。

https://codeforces.com/contest/512/submission/151456091

CF547E Mike and Friends

这题首先把区间问询拆成前缀问询,就相当于在线加入一些字符串,然后求第 i 个字符串出现了几次。

首先把树的结构建出来,插入字符串的时候直接在对应节点上做一个更新即可,然后问询的时候可以快速定位到这个字符串的点,然后做一个区间(fail 树上子树 dfs 序)的问询。

这个用 dfs 序配上 BIT 实现。

https://codeforces.com/contest/547/submission/151501389

CF559E Gerald and Path

f(i,j) 表示按照所有点的位置排序,前 i 个点,并且目前最右边达到(离散化后的)j 的最大覆盖长度。

考虑第 i 个点是向左还是向右。如果向右,那么有 f(i,pi)=f(i1,pi)+d(pi,j),其中 p,l,r 分别代表点的现有坐标,左边达到的最大坐标,和右边达到的最大坐标(都是离散化过的),d 代表现实距离。

如果向左延伸,我们先进行一个贪心的想法。如果 i 向左,并且目前右端点是 rj,并且 [j,i1] 中并不是全部向右的。我们发现这种状态一定不是最优,因为这些向右不会有任何有效的覆盖,向左一定不会更劣。考虑枚举 k 满足 [k+1,i1] 全部是向右的已确定其真实的最右边的点。设 x=maxi[k+1,i1],则有转移 f(i,x)=f(k,li)+d(li,x)

如果倒序枚举 k,容易发现 x 单调,于是可以维护一个关于 x 的最大值进行更新。

https://codeforces.com/contest/559/submission/152716761

CF605E Intergalaxy Trips

每条边有出现概率时的一个最短路。

凭直觉我们知道要倒着做。 du 表示 un 的期望最小值。我们走的路径一定是有 d 递减的,不然呆在原地总比去 d 更大的要好。

所以,一个点有两种决策:如果相邻点中不存在 dv<du,则呆在原地;否则往 d 最小的那个点走一步。设 qu 为前者发生的概率,gu 为所有 dv<duv 对于 u 的贡献,则有 du=qu(du+1)+gu,即 du=gu+qu1qu

为了按照拓扑序走,我们肯定每次找到 d 最小的点,然后更新它对周围的点的贡献。本质上转移图是一个 DAG。这点和最短路没有区别,所以这东西和 dijkstra 就差不多。

https://codeforces.live/contest/605/submission/152993416

CF585E Present for Vitalik the Philatelist

考虑枚举这个 gcdai,设其为 g。于是我们要分别处理出两个东西:一个是 x 的个数,即与 g 互质的数量;还有一个是 S 的个数,即 gcd=g 的集合个数。我们设 ci 表示序列中 i 的倍数的个数。

首先第一个,设其为 pi,做一个容斥得到 pi=j|iμ(i)ci。这是一个狄利克雷前缀和。

其次第二个,设其为 qi。暴力容斥不是很理想,但是若对其做狄利克雷后缀和 ri=i|jqj,则 ri 表示 gcdi 的倍数的集合数量,即 ri=2ci1,可以轻松得到。于是我们进行一次逆变换即可得到结果。

当然还要考虑一下怎么求 cc 其实就是这个数组构成的桶的狄利克雷后缀和。

https://codeforces.com/contest/585/submission/153265377

CF Gym 103470K

首先强制让一些边不连是非常难做的。所以考虑对于统计四元独立集,直接把它容斥了,变成了 11 种强制钦定一些边选,其他边随便的情况。其中第 11 种为所有边都需要选(四元团)的情况不好算,但是正好和最终所需要求的答案的那个东西抵消掉了,所以就不用管了。

然后对这 10 种情况分别考虑。通过计算三元环和四元环的数量,我们可以把所有 10 种情况都算出来。总复杂度 O(mm)

不能画图,放个官方题解:https://zhuanlan.zhihu.com/p/441174109

CF576D Flights for Regular Customers

感觉很有趣。

首先边排序,然后按照 d 从小到大分别加边,然后算出在加了这些边后得到的答案。加入第 x 条边时,我们要找到所有经过了恰好 dx 条边的点,然后以他们作为源,向外做 BFS 最短路。于是,在这次之后,我们每个点的答案应该为 dx+disu。然后用这个更新答案即可。

至于如何做经过了恰好 dx 条边的点,做一个 bitset 优化的矩阵乘法即可。也可以用一个倍增做法,维护 2k 的矩阵。

https://codeforces.com/contest/576/submission/153278065

CF571D Campus

很有趣的一道综合性的并查集题。

我们把它看做树,然后合并的时候启发式合并。由于不是很好同时处理两个集合的两种操作,于是我们考虑只打 tag,然后利用启发式合并的树高为 O(log) 的性质在询问时进行统计。这就需要记录时间。

对于两棵树的合并,记录他们合并的时间。对于一个清零,记录它清零的时间。对于一个整体加,记录一下这个加法的时间和前缀和——即对于点 u,假设给它一个加上 p 的命令,则新建一个 u 节点的操作,表示在时间 t 有一个加 p 的操作。对于每个节点,对这个按照时间排序的操作,我们维护其前缀和,这样就能快速算出在一段时间区间内的操作总和。

问询就比较简单了。我们不断从 u 往父亲爬,然后知道 v 子树清零的时间和这条边连上的时间。则这个点 vu 的贡献即这段时间区间里面的总和。

本文作者:LarsWerner

本文链接:https://www.cnblogs.com/TetrisCandy/p/16167743.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   LarsWerner  阅读(74)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起