2021.3做题记录

xsy1722B 边

发现要求的一定是一个环
发现这是一个偶正则图,说明一定是有欧拉回路的
欧拉回路对于一个点有入边和出边
对于入边和出边一定是一一匹配,顺序是无所谓的
所以我们给边定向
每个边要选一条出边和一条入边,所以我们只需要二分图匹配一下即可

\(\mathcal O(n\sqrt n)\)

code

CF587F Duff is Mad

之前有一道和他很像的题目 Mike and Friends
这题就比那题显然要难很多
这题相当于是,把 \(endpos[l]\sim endpos[r]\) 的子树 \(+1\) 后,\(s_k\) 串上每一个点的权值和
考虑对于所有 \(|s_k|\leq \omega\)\(|s_k|>\omega\) 的分开考虑
对于 \(|s_k|\leq \omega\) 的,我们可以把所有的询问离线,每个询问拆成 \(l-1,r\) 两个前缀询问
然后从 \(1\)\(n\) 暴力把 \(endpos_i\) 的子树 \(+1\),然后询问的时候暴力计算答案即可
这样做的复杂度是 \(\mathcal O(n\log n+q\omega \log n+q\log q)\)
对于 \(|s_k|>\omega\) 的,我们把所有的询问离线,每个询问拆成 \(l-1,r\) 两个前缀询问
显然这一类串最多只有 \(\dfrac{n}{\omega}\) 个(我们设 \(\sum |s_i|\)\(n\) 同阶)
我们对于每一个这类串的询问放在一起考虑
把这个串的每一个点 \(+1\),对于 fail 树上的点统计子树和
来了一个就把 \(sum\) 加上 \(endpos\) 位置的子树和
这样做得复杂度是 \(\mathcal O(\dfrac{n^2}{\omega}+q\log q)\)
经过简单分析可知,在 \(\omega=\sqrt\frac{n}{\log n}\) 时复杂度最低,为 \(\mathcal O(n\sqrt{n\log n})\)

code

P5332 [JSOI2019]精准预测

显然 2-sat 建图
问题变成了 \(T+1\) 时刻,\(i\) 活着能到几个死的,以及能不能到他死了的位置
这个问题可以 bitset 解决。
但是空间会炸
所以我们分块以下,一次只处理这个块里面的。

code

P4156 [WC2016]论战捆竹竿

一道货真价实的黑题。
可能可以算做过的最难的题了。

显然我们每次重复接的部分是一个 \(border\),相当于每次在这个后面接了一个他的 \(period\) 的长度。
考虑 \(30pts\) 的做法,我们可以把所有可以接的长度都算出来,然后跑一遍同余最短路,用 \(dis_i\) 表示走到模意义下的 \(i\) 至少要多少即可,复杂度为 \(\mathcal O(n^2\log n)\)
考虑如何优化这个做法
这里就需要我们去探究 \(period\) 的性质

Theorem

对于一个字符串,他的所有 border 从小到大排列之后,一定可以划分成若干段,使得每一段都是等差数列,段数 \(S\leq \log n\)

Provement

Lemma:显然,对于字符串的两个 \(period\) \(A,B\),如果 \(\max(|A|,|B|)+\gcd(|A|,|B|)\leq n\),那么 \(\gcd(|A|,|B|)\) 也是原字符串的一个周期

设原字符串最短的 \(period\)\(B\)\(A\) 为任意一个 \(\leq \frac{n}{2}\)\(period\)
并且显然他们满足 Lemma
所以 \(\gcd(|A|,|B|)\) 也是原字符串的一个 \(period\)
又因为 \(B\) 为最短的 \(period\)
所以 \(|A|\)\(|B|\) 的倍数
所以这一部分的周期一定是一个等差数列的形式。
所以长度小于等于一半的周期构成等差数列
即长度大于等于一半的 border 构成等差数列
然后分治下去,最多 \(\log\) 层,定理得证

考虑知道这个之后怎么接着往下搞
我们可以把一个等差数列放在一起搞
设这个等差数列为 \(a,a+d,a+2d,a+3d\)
\(\bmod a\) 意义下来搞这个东西
发现会形成 \(\gcd(a,d)\) 个环,把这些环分开处理
发现环上 \(dis\) 最小的那个点一定不会更新,从这里开始 dp 即可
同时观察到转移的时候 \(i\) 最多只能转移到 \(i+kd\),所以我们用单调队列维护一下这个东西。
还有一个问题 \(dis\) 在不同模数之间的转换
这个问题我们可以借鉴上面的做法,但是因为没有距离的限制并不需要单调队列

总的复杂度就是 \(\mathcal O(n\log n)\)

code

P3714 [BJOI2017]树的难题

考虑点分治
对于重心的出边,我们把相同颜色的放在一起考虑
用一个线段树维护,每次查询一下即可
考虑不同颜色之间的贡献,我们可以再开一个线段树,每次当颜色发生变化的时候线段树合并一下即可

code

CF868F Yet Another Minimization Problem

发现二次函数是凸的,所以可以决策单调性优化 dp,但是发现这个 \(cost\) 没有办法 \(\mathcal O(1)\) 计算,所以不能用普通的二分决策单调性
所以考虑一波分治决策单调性
\(solve(l,r,ql,qr)\) 分治,表示区间 \([l,r]\) 的最优决策在 \([ql,qr]\)
每次用 \([ql,\min(mid-1,qr)]\) 计算 \(mid\) 的最优决策 \(k\)
然后左右递归 \(solve(l,mid-1,ql,k)\)\(solve(mid+1,r,k,qr)\) 即可
这个时候我们可以暴力计算贡献,因为端点只会被移动 \(\mathcal O(n\log n)\) 次,类似于一个莫队的方法即可
最后的总复杂度也是1个 log 的

code

CF504E Misha and LCP on Tree

显然维护一个树上哈希。
注意到路径有一段向上的,有一段向下的,所以我们两个方向上分别维护。
二分 lcp 长度,然后问题变成了如何快速查询
\(\mathcal O(n\log n)-\mathcal O(\log n)\) 的树上k级祖先会超时
所以需要长链剖分,复杂度变成一个 log
当然可以继续优化,即把 lca 换成 \(\mathcal O(n\log n)-\mathcal O(1)\)
当然这样还是一个log,但是常数小一些

code

CF505E Mr. Kitayuta vs. Bamboos

一眼看上去就是一个二分
发现 check 貌似非常简单?
这题 2900?
然后发现,我们的 \(h_i\) 是不能减到负数的,这会导致我们 check 的时候的贪心策略非常难以选择。
于是就没法搞了。。。
考虑这么做的时候,我们需要把“最后尽量快的变到 0 的”最后做 \(-p\) 的操作
但是问题是我们不知道他们最后变成了什么
所以考虑倒序处理,即我们先让每个竹子的高度变成 \(x\),然后我们每天变矮 \(a_i\),每次可以拔高 \(p\)
只需要看最后的 \(h_i\) 是不是都不小于题面里的 \(h_i\) 即可
考虑贪心,我们维护每个数还有几次 \(<0\),然后我们优先取快的,如果这么做还不行,那就是 \(false\)
注意不能每次更新高度,否则复杂度炸裂,所以我们对于每个位置维护 \(cnt\) 表示他 \(+p\) 了几次。
\(\mathcal O(n\log n)\)

code

CF521D Shop

考虑贪心
显然要赋值尽量先赋值,并且显然只会赋一次
如果做了乘法再做加法,显然没有先加法再乘法优
并且赋值的那一次一定是最大的那个 \(b\),可以转化成一次加法
接下来问题变成了选那些,最后只需要把选的按照 \(opt\) 的大小输出即可
选的过程中,一次加法会让答案乘上 \(\dfrac{x+b}{x}\),一次乘法会乘 \(b\) ,用堆维护取最大的几个即可

\(\mathcal O(n\log n)\)

code

[xys1743B]最长公共子串对

考虑正着建 S 的 SAM
然后用 T 在上面跑匹配
设 现在匹配到 T 的第 \(i\) 位,那么可以求出 S 中最靠前的前缀包含匹配的长度,即在 parent-tree 子树中的最小值
同样匹配完了之后,我们可以求出 SAM 上每个节点第一次作为 T 的前缀的子串出现的次数
这样我们的最长公共子串一定在这些里面
对于后缀同样这么做
然后问题转化成了一个二维数点的问题。

code

P7415 [USACO21FEB] Count the Cows G

显然我们看题目中给出来的那个图就能看出来满足条件的点是一个分形。
考虑把询问拆成两个前缀
所以我们构造两个函数
\(query(x,y,k)\) 表示 \(k\times k\) 矩形中,以 \((x,y)\) 为右下角的 1 的个数
\(solve(d,k)\) 表示 \(k\times k\) 矩形中,\(y=x+d\) 上的 1 的个数
然后分治下去做就好了
不难发现复杂度为 \(\mathcal O(q\log_3^2n)\)

code

P7413 [USACO21FEB] Stone Game G

枚举 \(s_1\)
发现值域数轴被分成了好几段
如果所有段都是偶数,那么第一个人选 \(x\),第二个人也跟着选 \(x\) 即可,这样先手必败
如果有一段是奇数,那么先手直接选第一个是奇数的那一段,这样留给第二个人的全是偶数,所以先手必胜
但是问题是我们人为规定了 \(s_1\)
所以我们只需要判断第一个人能不能数列每一段都全偶即可

\(\mathcal O(n\ln n)\)

code

P3320 [SDOI2015]寻宝游戏

类似于虚树的思想,我们求出 dfn 之后,对于给定的一些点,走完的代价应该是

\[dist(a_1,a_2)+dist(a_2,a_3)+\cdots+dist(a_{k-1},a_k) \]

其中 \(a\) 为点按照 dfn 排序

如果插入一个点 \(x\) ,我们就找到dfn 左边已经在里面的和右边的 \(y,z\)

\[\Delta=dist(x,y)+dist(x,z)-dist(y,z) \]

删除同理
使用平衡树维护即可 一个log
code

P4211 [LNOI2014]LCA

我们可以考虑拆询问变成前缀和的形式
问题变成了点 \(x\) 和已经加进去的一些点的 \(LCA\)\(dep\) 之和。
考虑 dep 相当于是 \(x\) 到根节点上经过的点的数量
对于加入一个点,我们把这个点到根节点上路径上每个点的权值 \(+1\)
询问的时候直接查询那个点到根节点路径上的点权和即可

\(\mathcal O(n\log^2 n)\)

code

P3514 [POI2011]LIZ-Lollipop

发现一条有意思的性质
如果 \(k\) 可以,\(k-2\) 显然可以
考虑反过来,如果 \(k\) 可以,\(k+2\) 什么时候不可以
当且仅当这个区间 \([l,r]\) 有一边顶到了边界,另一边的下一个是 \(1\)
所以我们找到倒数第一个和倒数第二个 1,正数第一个和正数第二个 1,然后分别模拟一下即可
复杂度为 \(\mathcal O(n)\)

这题的升级版为 蝴蝶与花
带修改,求最靠左的
考虑先找到 \([1,p]\),使得 \(sum(1,p)=x+1\)(如果存在 \(sum(1,p)=x\) 直接输出)
然后逐渐往右移动这个区间,假设现在到了 \([l,r]\)
如果 \(a_{r+1}=1\),合法区间为 \([l+1,r+1]\)
否则如果 \(a_{l}=1\),合法区间为 \([l+1,r+1]\)
否则递归找 \([l+1,r+1]\)
所以问题转化成了求 \(1\)\(p\) 右边最近的一个 1
上面两个东西都可以线段树二分实现,从而做到一个 log

注意这里的一个性质,\(a_p\) 一定是等于 \(1\) 的,但是 \(a_1\) 不一定为 1,所以二分的时候需要考虑一下这个问题。

code

P5369 [PKUSC2018]最大前缀和

看数据范围一眼状压 dp
我们用 \(f[S]\) 表示用 \(S\) 的集合,使得最大前缀和为 \(sum(S)\) 的方案数
\(g[S]\) 表示用 \(S\) 的集合,使得所有最大前缀和均 \(\leq0\) 的方案数
答案即为 \(\sum sum(S)\times f[S]\times g[S]\)
考虑 \(g[S]\) 的转移非常的简单
如果 \(sum(S+a_i)\leq 0\),那么 \(g[S]\) 可以转移到 \(g[S|2^i]\)
但是 \(f[S]\) 不太好搞
我们考虑从后往前确定这个序列,即我们枚举在开头加上一个数 \(a_i\)
如果 \(sum(S)>0\),那么 \(f[S]\) 可以转移到 \(f[S|2^i]\),注意这里是 \(sum(S)>0\),因为否则最长前缀和为 \(a_i\)
这样就可以 \(\mathcal O(n2^n)\) 顺利解决了

code

ARC114C-Sequence Scores

考虑两个位置如果可以同时操作,那么必须满足 \(a_i=a_j,\forall i<k<j,a_k\geq a_i\)
相应的,考虑相邻的两个大小相同的数,如果 \(a_i=a_j,\forall i<k<j,a_k> a_i\),就可以把答案减小 1
所以我们考虑一共减小了多少
即有

\[\sum_{i=1}^n\sum_{j=1}^{i-1}(\sum_{x=1}^m (m-x)^{i-j-1})m^{n-(i-j+1)} \]

发现只和 \(i-j\)\(x\) 有关,所以可以 \(\mathcal O(nm)\) 解决

code

P4606 [SDOI2018]战略游戏

显然把满足条件的点一定是割点
所以把虚树建出来
建出来之后统计有几个圆点即可
注意求割点的时候,只能弹栈到 v

code

P2664 树上游戏

考虑点分治
考虑查询到 x 的时候直接计算他到当前分治中心其他子树的答案
答案分成两类,假设分治中心为 \(u\)
对于 \(u\)\(x\) 的路径上出现过的颜色,贡献为分治中心其他子树的大小之和
对于没有出现过的颜色,贡献为 \(\sum siz[y]\),其中 \(y\) 为其他子树中的点,\(color[y]\)\(u-y\) 上的第一次出现
我们先整体 dfs 统计这个东西
考虑分治中心的每一颗子树,我们先清掉这个子树里的标记
然后计算答案
然后再把标记打回来即可

code

ARC112D-Skate

考虑一个 # 能干什么,如果 \((x,y)\) 是 #,那么如果 \(x\) 这一行是好的,那么 \(y\) 这一列一定也是好的
所以问题转化成了对于一个 \((x,y)\) 的 #,我们在第 \(x\) 行和第 \(y\) 列之间连一条边
我们的目标是把所有行连在一起,或者把所有列连在一起,用这两种目的去统计连通块个数,取小的就可以了

code

P6628 [省选联考 2020 B 卷] 丁香之路

显然这是要走一条欧拉路
我们需要添加最短的边,让其他的点的度数为偶数,让起点和终点的度数为奇数
显然我们把相邻的两个奇数点连在一起就可以了
但是这样搞之后图可能不连通
所以我们要对于这个东西缩点一下,然后加上最小生成树的两倍权值
但是这里我们把相邻两个奇数点连在一起是不优于把这两个奇数点之间的每个点连起来,因为这样可以花费不变,但是可以把更多的点连起来,这样最后最小生成树的权值会变小
复杂度为 \(\mathcal O(n^2+m\log m)\)

P7470 [NOI Online 2021 提高组] 岛屿探险

考虑把 \(b\)\(d\) 分开处理
我们把 \(b\)\(d\) 分别按照从小到大排序
对于一个 \(x\),右半边的 \(b\) 会对左半边的 \(d\) 产生贡献,左半边的 \(d\) 会受到右边的 \(b\) 的贡献
考虑第一类情况,问题转化成,有多少数和 \(c\) 异或小于等于 \(d\)
可以用 trie 树解决
对于 \([l,r]\) 只需要可持久化 trie 树即可
第二类的方法略微有些麻烦
我们可以把 \([l,r]\) 拆成 \([1,l-1],[1,r]\)
然后按照下标修改 \((a,b)\),我们在 trie 树上所有和 \(a\) 异或小于等于 \(b\) 的位置上打上标记
相当于是把上一个做法的询问变成修改,修改变成询问
但是我们不能枚举每一个 \(x\),所以把 \(b,d\) 放在一起排序,然后做 CDQ
复杂度为 \(\mathcal O(n\log^2n)\)

code

CF468C Hack it!

发现 \(x<9\times 10^{18}\) 的时候

\(f(x+10^{18})=f(x)+1\)

所以 \(sumf(0,10^{18}-1)+1=sumf(1,10^{18})\)

并且可以以此类推

所以我们只需要求出 \(sumf(0,10^{18}-1)\) 就可以直接构造出一组解了

code

posted @ 2021-03-03 11:46  YuukiYumesaki  阅读(140)  评论(0编辑  收藏  举报