灰色轨迹
记录题目的思维方式。
选取字符串
kmp;border 的性质;计数
同时有前后缀想到 KMP 求 border。注意到 border 之间形成树形的嵌套结构关系,于是树上容斥来求。
取石子
博弈论;位运算
博弈论往往先考虑特殊情形下的答案。 对于本题,容易发现的是 \(\sum a\) 为奇数时先手直接取 \(1\) 是必胜的。那么这意味着偶数情形时 一定会尽量取偶数的答案。那么考虑扩展这个结论。当取过 \(2\) 之后 $\sum a=0 \pmod4 $ 时,先手是必败的。于是得到的形式是如果当前所有 \(a\) 的异或和是 \(s\),其最低位的 \(1\) 是在第 \(k\) 位,若取值的上限已经是 \(2^k\),则先手必败。具体实现就不说了。
均衡区间
单调栈;二维数点
对于单点来统计贡献,容易想到的是单调栈预处理出每个点 \(i\) 最左、最右边能拓展到的下标,得到一个 \(L_j<i\),\(j<R_i\) 的判定条件。统计上,规约到二维偏序问题,套路地固定一维 \(i\) 开树状数组统计满足其中一个条件的,查找是否满足另一个条件即可。
禁止套娃
dp;差分
这种题目第一眼看上去其实像是 ddp,然而发现转移的形式较复杂且复杂度不可接受。注意到本质上数字分为外层序列和内层序列,二者之间是从属关系,于是考虑枚举内层序列的选择情况,用一个 dp 计算两个内层点之间有哪些外层的点。注意到 dp 的形式要求不能出现两个相同的 \(a\),实质上是 \(a_i\) 的上一个元素 \(a_j\) 之前的所有元素的 dp 值都要去除掉 \(dp_{i}\) 的贡献,于是考虑差分去计算这个东西。
P7114 [NOIP2020] 字符串匹配
kmp;border 的性质
初步的想法是枚举 \(C\),但这样得到 \((AB)^i\) 之后的处理是困难的,操作较为繁琐。枚举 \(C\) 相当于枚举 \((AB)^i\),于是我们不妨枚举 \(AB\),那么 \(\sum (AB)^i\) 是 \(n\log n\) 级别的,可以接受。对于判定前缀,由 kmp 的结论知道 字符串 \(s\) 的 周期事实上就是 \(|s|-\mathrm{nxt(s)}\),结合 \(\mathrm{nxt(s)\ge \dfrac{|s|}{2}}\) 的条件判断即可。对于 \(f\) 的限制,预处理出前后缀的奇数字符个数,枚举时容易动态统计。
CF965E Short Code
Trie;启发式合并
多个字符串的贪心问题是不好直接给出贪心策略的。和前缀有关的问题我们想到建出 Trie。于是题目的所求就是将 Trie 上一些关键点提到尽量浅的深度上。考虑 \(x\) 子树内的情形。当所有的子节点 \(y\) 都提好时,显然需要提 \(x\) 子树中深度最深的那个到 \(x\)。注意到树形结构不能简单地统计子树内的最大深度,子树里的所有点将来都有贡献的可能,于是启发式合并数据结构维护即可。时间复杂度是 \(O(n\log^2n)\) 的。
P9149 串串题
kmp;组合数学;双指针
考虑每种选择方案的权值是困难的,我们不妨套路地考虑得到每个最终匹配序列的方案数。具体地,先把 \(a\) 数组中和 \(b\) 数组相同的那一部分存为 \(c\) 数组跑 kmp,用 \(b\) 数组来匹配 \(c\) 数组。得到匹配的下标之后记录这一段之间有 \(t\) 个数不在 \(b\) 数组中,也就是这些数必须选。式子易得。对于 \(t\) 的统计,朴素做接受不了,但是 kmp 的过程匹配出的序列下标都是单调的,那双指针跑一遍就可以了。复杂度是 \(O(n)\)。
P9753 [CSP-S 2023] 消消乐
字符串;dp
初步的想法是找到每个 \(i\) 前面第一个可以消的 \(lst_i\),做 dp, \(dp_i=dp_{j-1}\)。 考虑 \(j\) 的求法。朴素的想法是暴力去求,但是这个复杂度第一眼比较玄学。注意到字符集很小,猜想复杂度和字符集大小有关,遇事不觉先打暴力,事实上确实如此。原因是每个字符只会被一种字符中的一个转移到。
P8819 [CSP-S 2022] 星战
哈希;随机化
注意到 \(n\le 5\times 10^5\),发现题目中的操作难以在 \(O(1)\sim O(\log n)\) 的时间内维护,离线下来同样没有很好的方法。考虑用非常规手法维护。注意到 "反击" 的限制和 "连续穿梭" 本质上是一样的,都是让所有点的出度是 \(1\)。考虑题目难维护的操作是将入度相同的点集做加删操作,而要求的是出度为 \(1\)。由于没有重边,若我们认为所有出度相同的边等价,发现合法情形的边权和一定。我们利用这个东西来做随机化:对出度相同的边赋相同边权,加删操作就容易 \(O(1)\) 完成了。
P6286 [COCI2016-2017#1] Cezar
拓扑排序
字典序问题就是维护一下字符集的偏序关系。然后拓扑排序就做完了。
CF1777F Comfortably Numb
异或差分;最值分治;Trie 合并;启发式合并
是各种套路综合在一起的题目。对于 \((l,r)\) 的异或区间和,其实相当于对 \(a\) 序列做前缀和得到 \(b\) 数组后的 \(b_{l-1}\oplus b_r\)。答案统计中的 \(\max\) 是难以处理的,考虑按 最值分治,形成一棵笛卡尔树在树上分治。对于异或的操作,套路地建立 01-Trie,插入子树内所有 \(b\)。暴力做显然是不优的,子树内的问题考虑类似启发式合并的思想,同时也是最值分治的基本套路,枚举 \(\mathrm{siz}\) 较小的,查询 \(\mathrm{siz}\) 较大的子树即可。查询完之后将 Trie 合并起来即可。这样的思想有些分治问题也可以使用。时间复杂度 \(O(n\log ^2n)\)。
树
容斥;状压;std::bitset
正常的做法是去考虑每一对 \((x,y)\),则边被遍历的次数是 \(\sum_{x\in S,y\in T}+\sum_{x\in T,y\in S}\)。但是这样当 \(x,y\) 都在 \(S,T\) 集合中时会算重,减去这一部分即可。实现上注意到 \(m\le 64\),可以状压成 unsigned long long 来做。不正常的做法是考虑在每一次都暴力枚举每一对 \((x,y)\),复杂度是 \(O(n^2m)\) 的,考虑优化。注意到 std::bitset 可以为我们提供 \(\dfrac{1}{32}\) 的常数,就做完了。
序列
贪心
考虑到 \(2,3\) 操作的内部排序方式一定是从大到小,还注意到 \(1\) 操作的本质和加上一个数没有区别,于是我们实际上规约为了如何对所有 \(a\) 的 \(2,3\) 操作来排序。我们所求的是 \(\prod a_i\),于是最好维护成一个乘积的形式。实际上对 \(x\) 加上 \(y\) 相当于 \(x\times \dfrac{x+y}{x}\),由于我们已经知道了 \(2\) 操作内部的排序方式,于是这样的系数是可求的,从大到小排序即可。加法转乘法的原因是所求为乘法,需要转化。
字符串
贪心;线段树
首先需要想到的是区间内怎样的串是最优的。对于一个 \(t\),显然将 \(s\) 中某一段具有 \(t\) 偏序关系的一段拓展成序列最优。也就是说在 \(t\) 排序的意义下求极长递增段的长度,也就是相邻逆序对个数。看到 \(k\) 很小,维护两两字符的取值有多少种即可。带修和区间查上线段树即可。
镜的绮想
C++ 语法
就纯弱智题。开桶记录每一个 \(x\) 上两个 \(y\) 相加的和即可。
万物有灵
贪心;dp;矩阵优化
其实是我做法复杂了。把阶段性的 dp 式子拆出来再矩阵优化。详情见题解。
白石溪
贪心
同时考虑两色的点很难受,于是考虑能否转为只依赖自身颜色的贡献。于是拆成每一个点贡献,红色的贡献是 \(\sum a_i+i\times d\),蓝色同理。考虑后者只和个数有关,于是先全部设为蓝色,将 \(a\) 排序去取即可。
上山岗
线段树二分;Hall 定理
朴素的想法是检查时对每个 \(w\) 找相邻最近的小于它的 \(c\)。考虑优化匹配方式。匹配问题想到二分图匹配,Hall 定理。对于本题,如果将 \(w\) 记为 \(-1\),那么 \(c\) 为 \(1\),放到序列 \(b\) 中做前缀和,那么 \(\operatorname{ans}=n+\min b\)。由于需要动态维护,上权值线段树。查询时线段树上二分可做。
交换
置换;结合律优化
\(n\mid m\) 时是好做的,套路地倍增置换矩阵转移即可。一般的形式下,考虑还是每 \(m\) 个做一次,这样一来置换出的形式需要左移 \(m\mod n\) 位后再进行操作,于是将置换增加一步即可。
CF1763C Another Array Problem
贪心
一般地,CF 的题目都会给至少 \(2\) 个样例,然而本题只有一个小样例,于是启发我们发现一些结论。naive 的结论想法是保持最大的不动,让最小值尽量地小。操作的形式是每次将一段数变为同一个数,因此任意两个数可以都置为 \(0\)。注意 \(n\le 3\) 时要特判。
CF1775E The Human Equation
贪心;前缀和
考虑到对子序列 \(\pm 1\) 的操作并不好维护。区间操作问题想到差分/前缀和。对于本题,对 \(a\) 进行前缀和后操作转化为了对前缀和数组 \(b\) 上的某些元素一起做 \(\pm 1\) 操作。于是用区间最大减去区间最小即可。
CF1290C Prefix Enlightenment
建图;并查集
每个点只在两个集合中,容易知道的是 \(a,b\) 两个集合的情况根据 \(S_i\) 的取值分为全选/不选/只选一个。事实上这些个限制形成了一张图。维护限制的问题想到建图解决。对于本题,我们要知道的是每个点选择集合时为了保证限制还要选择其它那些点。每个点拆成选和不选两个状态,由于是一个动态加点的过程,而且只需要维护连通性,于是带权并查集可以解决。
CF1389F Bicolored Segments
dp;线段树
注意到 \(t\) 的限制较容易,于是先满足线段不交的限制。设 \(dp_{i,j}\) 表示到了 \(i\),\([j+1,i]\) 和 \(i\) 颜色相同。考虑转移时会新加入一些 \(r=i\) 的线段,同时这些线段需要满足 \(l>j\)。也就是要将 \([0,l-1]\) 区间的 dp 值 \(+1\),那么上两棵线段树维护即可。
CF1580D Subsequence
最值分治;树形背包
观察这个式子就发现 \(f(i,j)\) 这个东西很亮眼。见到序列最值考虑序列最值分治。然后这题其实就做完了,合并最小值左右两边的答案即可。时间复杂度和树形背包是一样的,是 \(O(n^2)\)。
CF1720D2 Xor-Subsequence (hard version)
Trie;dp
\(O(n^2)\) 的 dp 是容易想到的,和最长上升子序列一样做。考虑优化。状态的定义难以优化,考虑优化转移,找到最大的 \(dp_j\) 满足 \(j,i\) 之间的关系。异或问题建出 Trie 树,找到两个值第一个不相同的位就可以判断了。于是想到 Trie 树优化 dp。考虑同时维护 \(a,b\) 两者复杂度不可接受,于是考虑 \(x,y\) 某相同的条件 \(a_x\oplus y=a_y\oplus x\) 不好维护,将等号两边转为只与 \(x\) 有关的形式就变为 \(a_x\oplus x=a_y\oplus y\),用这个建出 Trie 树并记录 \(a\) 此时的情况即可。时间复杂度是 \(O(n\log V)\) 的。
AGC056C
图论建模;欧拉路;贪心
注意到选择 0,1 个数相同的串等价于将原数组做前缀和之后选择两个前缀和相等的位置。这种无从下手,不知道如何处理的题目往往可以考虑转换题意,进行图论建模。我们将每个 \(d_i\to d_{i+1}\) 建一条边,考虑新的 \(d_i\) 就是原先的 \(d_{r+l−1−i}\),那么相当于将边翻转;又因为前缀和相同,也就是将一个环反着走一遍。于是我们要找到字典序最小的一条欧拉回路。这个考虑贪心,能走 0 就走 0,否则就走 1。
CF193D Two Segments
线段树
首先枚举两个区间显然不现实。考虑转化为枚举值域 \([l,r]\)。常见的套路是在加入每个 \(r\) 时记录其右端点的贡献。我们现在要统计 \(l\in[1,r-1]\) 中 \([l,r]\) 的贡献。考虑加入 \(r\) 后先当作一个新的块,也可以和它 \(a\) 数组两端位置的块合并。于是线段树维护区间的最小值和取值次数。注意到当 \(\min=1\) 时,\(\min=2\) 的情形同样可以做贡献。于是也记录次小值的出现次数。
随机游走
贪心
直接写出式子贪心即可,没啥难的。
分发奖励
线段树
维护出现的次数是困难的,因为有些点会出现多次,于是不妨维护最小值和其出现次数;考虑到每个点对它子树内的所有点都有贡献,不妨在 dfs 的过程中动态对线段树进行维护。这种弱智题想不到是不应该的。
卡路里
二维差分;单调栈
首先注意到最小的方案一定是直接走完一个 \([l,r]\)。这就有 50pts。对于 100pts,考虑转而计算每种奶茶的贡献,显然每种奶茶只在一个自己作为最大值的区间里有贡献,这个区间可以写为 \([l1,l2],[r1,r2]\) 的形式,查询就是 \(O(1)\) 的。
传话游戏
区间dp;多项式;拉格朗日插值
注意到一个元素删去之后不会加回来,于是考虑记录每个元素的删除时间 \(t_i\)。于是不合法的条件是 \(j>i\) 且 \(t_j>t_i\) 且 \(t_{[i+1,j-i]}=0\)。于是关注序列中此时的最大值,让左边的部分满足限制条件去 dp 即可,要做前缀和优化。考虑进一步优化。注意到 \(dp_{x,x}\) 的项数是 \(1\),我们认为其是 \(0\) 次多项式,那么 \(dp_{r-l+1}\) 就是 \(r-l\) 次多项式。\(sum=\sum dp\),于是 \(sum_{1,m}\) 是 \(m\) 次多项式。那么上拉格朗日插值优化即可。
CF865D Buy Low Sell High
反悔贪心;堆
simple 的想法是去维护一个 dp,但是发现有整体移动的操作,难以维护。首先想到的贪心策略是维护一个记录最小值的堆,每次都和里面最小的进行匹配。但这样做是错误的。原因是不一定在你统计的时候就卖出某张股票,或许之后才会卖。解决的办法是考虑到对于 \(i<j,v_i<v_j\),买 \(j\) 时 \(i\) 一定会买;又注意到 \(v_a-v_c=(v_a-v_b)+(v_b-v_c)\),于是每次再将 \(v_i\) 加入堆中一次来维护可能更优的情形。可以认为第一次加入维护的是自身的贡献,第二次加入维护的是在这里抛售的那个股票的贡献。这是反悔贪心的一种。反悔贪心往往可以做差来发现一些奇妙的性质。
CF55D Beautiful numbers
数位dp;记忆化搜索;状压;dp优化
对于 \(n\le 9\times 10^{18}\),看上去用矩阵/多项式的 \(O(\log n)\) 不太可做,在 \(n\) 较大时同样可以考虑数位dp。分别维护关于 \(2\sim 9\) 的模数较为繁琐,然而注意到 \(\operatorname{lcm}(2,3,\cdots,9)=2520\),实质上维护关于 \(2520\) 的模数即可。对于记录每位数是否出现,暴力状压是不优的,注意到当且仅当所有选择的数的 \(\operatorname{lcm}\) 是原数关于 \(2520\) 模数的因数时才合法,而 \(2\sim 9\) 中这样的模数只有 48 个,于是记忆化搜索完事。

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号