【加油做题】每日小题集٩(๑>◡<๑)۶
再爱虹蓝一万年!
CF813D Two Melodies
一个妙妙的想法:最开始考虑暴力,即枚举一个字符串,再构造另一个字符串使得两个字符串长度之和最大。但这样会出现两个字符串有交集的情况,所以定义 \(f[i][j]\) 表示以第 \(i\) 和第 \(j\) 个位置结尾的两个字符串最长的长度(显然 \(f[i][j] = f[j][i]\),所以假设 \(i < j\)),那么可以认为以 \(i\) 为结尾的字符串后不再接新的字符,只向 \(j\) 后添加大于 \(i\) 的字符,这样一定不会有重复的部分出现。再通过桶优化一下转移即可。
CF325E The Red Button
分析题目性质:1.当 \(n\) 为奇数时一定无解。因为能到达 \(0\) 和 \(n - 1\) 的只有 \(\frac{n - 1}{2}\),显然无解。 2. 当 \(n\) 为偶数时, \(i\) 与 \(i + n / 2\) 所能到达的点是相同的,且没有其他的点能够到达它们所能对应的点。那么我们可以把点看作边,可以证明存在欧拉回路。
CF37E Trial for Chief
反向考虑问题:要把所有的点都染成白色,最少需要几步?不难发现可以把同一联通块缩成一个点,那么此时就变成了一棵树,每次操作都可以从一个点向外扩张一步。那么最短的显然是这棵树直径的一半,因为数据范围很小直接暴力从每个点bfs就行了。
CF875F Royal Questions
对于一个公主的两个选择,我们把对应的王子连上一条边。那么这条边的指向就代表了公主的选择。考虑构造合法的图,一个 \(n\) 个点, \(n\) 条边的联通块一定可以构建成一棵合法的基环外向树。此时也一定是最大的:因为所有的王子都已经匹配上了。所以把边从大到小排序,贪心的用并查集合并联通块。
Bzoj4017 小Q的无敌异或
位运算——按位考虑。考虑第 \(k\) 位上以 \(r\) 为右端点的区间的异或和,那么只需要知道 \(1\) 的个数是偶数还是奇数就可以了。\((sum[r] - sum[l - 1]) \ mod \ 2^{k + 1} \in [2^k, 2 ^ k + 1)\) 说明这个区间为 \(1\),那么就使用权值线段树查询限定区域的左端点有多少个。复杂度 \(nlog^{2}n\)。
Bzoj4771 七彩树
树链的并 & 主席树 & set。考虑如何用树上差分来求解一个点的子树内有多少个不相同的颜色,将所有相同颜色的点放在一起考虑。首先按时间戳排序,第 \(x\) 个点产生的贡献就是把 \(x\) 到根的路径上的点全部 \(+1\),再把与 \(x - 1\) 的 \(lca\) 到根的路径上的点全部 -1。发现这样可以支持按照深度不断插入新的点,维护主席树,在对应的位置上查询即可。
Bzoj3881 Divljak
考虑对所有的 \(S\) 串建立AC自动机,那么考虑新加入一个字符串对所有的串所产生的影响。即为对所有 \(T\) 的前缀所对应的节点在 fail 树上到根的链+1,这个用树链的并可以完成;一个串是后来多少个串的子串就单点查询即可。
CF1109E Sasha and a Very Easy Test
最大的问题在于模数并非一定与乘数互质,不一定存在有逆元。那么这时应当把与模数互质与不互质的部分分开考虑。将模数质因数分解后,每乘上一个数把与模数互质的部分放入一棵线段树上,乘除的时候直接乘逆元;不互质的部分分解质因数,分别存在BIT中记录下指数,除的时候做减法就行。
Bzoj5210 最大联通子块和
动态dp,根据套路把树轻重链剖分,重链和轻链分别维护。即重链用数据结构维护答案,轻链暴力修改就可以保证修改的复杂度,因为在一个点到根的路径上只会有不超过 logn 条轻边。考虑 dp \(f[u] = max(val[u] + \sum f[v], 0)\),那么把轻重链分开考虑:\(f[u] = max(g[u] + f[v], 0)\) 其中 \(g[u]\) 为 \(u\) 的所有轻儿子的 \(f\) 值之和加上 \(val[u]\)。发现这个形式其实就是从 \(u\) 开始的最大前缀和,在线段树上维护即可。至此我们实际上已经可以单点询问出 \(u\) 的 \(f\) 值。但是还需要求出子树内的 \(f\) 值的最大值。还是分别考虑,重链上的部分就是最大子段和。再考虑轻边所连接的若干条重链的贡献,我们求出它们的最大值赋值给 \(u\) 所在线段树上的叶子结点的最大子段和的初值就可以维护了。
Bzoj2906 颜色
维护 \(f[i][j][k]\) 表示第 \(i\) 块到第 \(j\) 块之间的颜色在 \(1\) 到 \(k\) 之间的权值和,以及 \(g[i][j][k]\) 表示第 \(i\) 块到第 \(j\) 块之间颜色为 \(k\) 的权值。整块部分直接前缀和,零碎部分暴力即可。计算取块的大小为 \(n ^ {\frac{2}{3}}\) 时是最快的。
Bzoj5206 JSOI2017原力
当所需求的东西不好使用数据结构维护且数据范围较小时,不妨考虑暴力一些的根号分治做法。这题就可以对度数 \(>=\sqrt{m}\) 的点与小的分别处理。当一个三元环中仅有大点直接枚举,有小点的时候枚举小点 & 两条出边看是否符合情况。这样的复杂度是 \(m\sqrt{m}\) 的。要注意保证所统计的内容不重不漏。
Bzoj4182 Shopping
这题要求任选出一个连通子图,那么考虑用点分治处理,每次仅考虑一定包含根节点的连通子图。直接用子树对父亲转移的方法的话复杂度是 \(nc^{2}\) 的, 但可以使用一种新的背包方式,即定义 \(f[i][j]\) 表示考虑了\(dfs\)序中 \(i -> n\) 的节点时,花费代价为 \(j\) 所能获得的最大值。如果要选择子树,说明当前点必须选择,如果不选当前点,就跳过子树在 \(dfs\) 序上面的一整个段转移。这样做的复杂度仅为 \(nclogd\)。
Bzoj4631 踩气球
把询问放到线段树上,最多不会超过 \(logn\) 个区间。记录下每个询问被拆到了多少个区间。每修改一个点,把路径上所有的区间的和值 \(-1\);如果发现区间和 \(= 0\),把该区间上的询问记录的值\(--\),发现\(=0\)那么把答案\(+1\)。
2.22 - T1 Toll
发现如果直接使用最小割,可能会有非法的情况。即对于一条边的两端 \(u,v\) 而言(只考虑 \(1\) 能到达的 \(u\) 和能到达 \(T\) 的 \(v\)),当\(v\) 在源,\(u\) 在汇的时候说明非法,因为可以从\(S\)走到\(u\) 收费一次,从 \(u\) 再走回 \(v\),再从\(v\) 走到 \(T\) 收费一次。添加一条从 \(v\) 到 \(u\) 的为 \(INF\) 的边就能保证不被割到两侧了。
2.22 - T2 Graph
求 \(n\) 个点带标号的边权为 \([1, m]\) 的不同二分图的个数。令 \(ans[i]\) 为 \(i\) 个点的答案,那么我们可以考虑枚举最后一个放入的联通块的大小:\(ans[i] = \sum_{j = 0}^{i-1}f[j + 1]*ans[i - j - 1]*\binom{i-1}{j}\) (其中 \(f[i]\) 代表有 \(i\) 个点的连通二分图数量)。求\(f[i]\):容斥求解。令 \(g[i]\) 表示 \(i\) 个点的二分图数量,其中不连通的部分分别属于黑白集合算不同的方案,但全部取反算一种方案。 \(g[i] = \frac{1}{2}*\sum_{j=0}^{i}\binom{i}{j}(m + 1)^{j*(i-j)}\)。(\(\frac{1}{2}\)表示排除了所有点反色的情况)。使用 \(g\) 递推 \(f\),则枚举1号点所在的集合大小。\(f[i]=g[i]-2 * \sum_{j=0}^{i-1}f[j+1]*g[i-j-1]*\binom{i-1}{j}\) 其中\(*2\) 表示所选中的集合反色之后与外部集合构成的方案也被计算了一次,要减去。这样就可以求出 \(ans\) 了。
2.23 - T3 Recompile
使用 LCT + 全局线段树维护。当有换根的时候,如何在线段树上维护子树信息?令当前根为 \(root\),求的是 \(x\) 的子树信息。1.若 \(x = root\),查询整棵树。 2. 若 x 在原树上是\(root\)的子树或其子树不包含\(root\),那么直接查原来的区间即可。3.若\(x\)是原树上 \(root\) 的祖先,那么 \(x\) 现在子树所包含的部分为整棵树除去原来包含 \(root\) 的子树。
Bzoj3470 Freda's Walk
可以先计算出到达每个点的概率,与从每个点出发的期望。那么可以枚举每条边\((u,v)\)计算出从 \(u\) 出发期望的路径长度的变化值就可以实现 \(O(1)\) 计算删边对于答案的影响了。
Bzoj4675 点对游戏
因为每个点被选择的概率相同,所以每个点对被选择的概率也是相同的。而每个人所选择的点对独立,分开来考虑。所以在一个人第 \(i\) 次操作选到固定点对的概率是 \(\frac{i- 1}{n - 1} * \frac{1}{n}\),那么这个概率乘上幸运点对的个数 \(*2\) 就是选到幸运点对的概率。把选到所有幸运点对的概率相加,就是所求的期望。
Bzoj4662 Snow
可以按照清洁工的编号建立出一棵线段树。那么每一次清洁工清扫所会影响到的清洁工都是一段连续的区间。每次暴力扫所有涉及到的清洁工,维护一棵支持区间减法,单点+INF,即查询区间最小值即可获得此时区间长度最小的清洁工。注意到每次修改所涉及到的人的区间都会变成左端点相同 \ 右端点相同。那么对于左端点 \ 右端点相同的一段我们可以一起处理,因为它们的编号也必然是连续的一段。使用并查集分别维护一下即可。
Bzoj4665 小w的喜糖
容斥 + dp。考虑容斥,即用全集 - 有 1 个和自己相同的 + 有 2 个和自己相同的……用 dp 求解。设立状态为 \(f[i][j]\) 为最开始糖果种类为 \(1,2...i\) 的人中有至少 \(j\) 个和自己相同的方案数。如何处理?**在 dp 的过程当中先把所有的糖果种类看成是不相同的(解释:可以看做现在每颗糖果拥有了两个属性,一个是种类,一个是两两不同的编号。那么此时 dp 状态变为 \(f[i][j]\) 表示至少 \(j\) 个人拿到了和自己同种的糖果,但不要求是自己原来的那一颗)。这样算出来的会重复计算因为相同的糖果交换位置其实是一种方案,所以最后再除以 \(\prod p[i]!\) (\(p[i]\) 为糖果种类为 \(i\) 的人的个数)。
dp方程:\(f[i][j]=\sum f[i - 1][j - k]*C\binom{k}{p[i]}*P\binom{k}{p[i]}\)
XSY2166 Hope
%YWW 考虑从小到大插入所有的数字,可以发现如果把数字 \(i\) 放在第 \(j\) 个位置,那么前 \(j\) 个位置都会是连通的,而后面的 \(i - j\) 个位置都不会和前面的连通。令 \(f[i]\) 表示前 \(i\) 个数字的所有排列方案的 \(Q\) 之和,于是可以转移。套路把组合数拆开使用分治FFT优化转移。
XSY2714 大佬的难题
%YWW 三维偏序,但给定的是排列。考虑容斥求解,使用二维偏序来容斥出答案。直接看yww大佬博客吧QAQ
XSY2718 Gift
分数规划的问题,先二分答案转化为判定最大收益是否大于0。可用最大闭合权子图来实现,\((S, p[i] / q[i], INF), (S, x[i], b[i]), (x[i], p[i] / q[i], INF), (p[i] / q[i], T, a[i] * mid)\)。但这样边数与点数太大是不可接受的,于是考虑优化建图。建图 \((S, p[i] / q[i], a[i] * mid), (p[i], q[i], \frac{1}{2} b[i])\) \(,(q[i], p[i], \frac{1}{2} b[i]), (p[i] / q[i], T, \frac{1}{2} b[i])\)。这样能够保证只存在同时割去 \(a[i] * mid\) 或 \(b[i] / 2\) 的情况。容量为分数没关系,所有的*2即可。
XSY2732 Decalcomania
不妨认为会从 \(0\) 开始向右走到一个端点后折返再走到一个左端点。显然当固定了左右端点的时候,在这个区间内印的印花肯定是贪心选取,即印花的个数固定。对于每一个走到的右端点\(i\)求出最优的左端点位置 \(f[i]\) ,发现这个是具有决策的单调性的。那么可以分治优化决策单调性dp,每次暴力扫描。走过的区间一定是连续的一段,建立主席树可以在主席树上二分计算印花的个数。
XSY2709 Count
构造序列,一般采用插入的方法来实现。从小到大向序列中插入数字,设立 \(f[i][j][0/1][0/1]\) 表示前 \(i\) 个数字,一共形成了 \(j\) 个段的方案数。‘段’的含义是段中不允许再插入数字,但段与段之间仍可以插入。\(0,1\) 状态记录下开头和结尾有没有填上。
UOJ NOI Round#1 T3 火车管理
使用一棵线段树来维护栈顶和,那么区间入栈的操作 = 区间赋值。单点弹栈我们需要知道当前点入栈之前的上一个节点是谁(权值大小)。所以使用可持久化线段树,对于每个时刻维护每个铁路的栈顶元素入栈的时间。我们查询到当前栈顶的入栈时间之后,查前一个时刻的栈顶值就可以了。
LOJ6515 贪玩蓝月
1.离线做法:线段树分治。记录出现和消失的时间,分治的时候直接在每一层都开一个新的背包数组(可以回收一下,防止爆空间)。
2.在线做法:维护两个栈,每次添加物品新开一个背包把物品加进去,删除物品就弹栈(即维护背包的前缀和)。如果发现有一端个数为 0 仍要删除,那么就暴力把另外的一边拆成两半放到两边。复杂度:只需证明暴力分开的即可。主定理\(T(n) = O(n) + T(\frac{n}{2})\),是线性的。询问的时候把其中一半丢到线段树上,枚举另一半的选择。那么此时前一半的值是一个区间(或两个),在线段树上查一下 max 就能得到答案。
CF687 D-Dividing Kingdom II
先从暴力的角度出发,把所有的边从大到小排序。如果两条边连接的点不在同一个联通块当中,连接并标记为在不同的集合中。如果在同一个联通块中并且在同一个集合中忽略。否则输出答案。会发现第二种边去掉对于答案是没有任何影响的,那么在线段树上归并求出一个区间内的关建边,这样边的数量只有 \(O(n)\) 的级别。查询也是归并后直接暴力做。使用带权并查集来维护点与点‘不在同一集合’的关系。
Bzoj5048 塌陷的牧场
反向去考虑问题,即从障碍出发看每次新覆盖了多少个点。每个点维护一下四个方向上的并查集,并查集维护这个方向上最近的未被覆盖的点。暴力跳直到发现所指向的点是自己为止。
洛谷3月月赛 序列
详细题解:洛谷。在这里记录几个关键的点:1.转化图计数为序列计数,序列不同一定本质不同,只需要关心是否存在满足序列要求的图即可;2.是否合法——尽量根据最优方案构造符合序列的图,找到边数,强连通分量与变化次数所需要满足的限制(充要条件),然后限制转移。3.优化dp,优化状态的数量。可以对限制条件进行化简,找到每个状态维度存在的意义,在不需要的时候直接删掉。
洛谷P3059 同时平衡线
如果 \(k = 1\),我们可以考虑求出与每个右端点相匹配的左端点,此时以该端点为结尾的合法子段个数为 \(f[r] = f[l] + 1\)。把这个dp扩展到 \(K\) 维的情况:考虑一段是合法子段的充要条件:(把左括号看做+1,右括号看做-1)\(sum[l - 1] = sum[r], min(sum[k] (k \in [l, r])) >= sum[l - 1]\)。分别维护这两个限制:1.枚举左端点,找到最近的 \(x\) 使得 \([l,x]\) 中的前缀和都是非负的;2.使用扫描线和 \(map\) 计算当前范围内最前面的和 \(sum[l]\) 相等的 \(sum[r]\) 在哪里。
3.05 - T1 Marshland
拆成危险点(危险点拆点两个中间通一的流量),奇点和偶点跑费用流即可。
3.05 - T2 Party
霍尔定理。每个人如果带了 \(x\) 种产品,可以看做是 \(x\) 个人,与特产一一对应。霍尔定理:在一侧中任意取 \(k\) 个点,在对侧都有至少 \(k\) 个点与之对应。那么可以 \(2^{c}\) 枚举左侧的人,用线段树 + bitset求出对应的特产集合大小为 \(S\),那么说明 \(x\) 的最大值是 \(\frac{S}{p}\) (\(p\) 是当前人数)。取所有 \(x\) 最大值的最小值就可以了。
3.05 - T3 Platform // 洛谷4143 采集矿石
后缀数组。字符串的任何一个子串,都可以看做是一个后缀的前缀。当字符串长度递增,排名递减但权值递增。所以我们可以枚举每一个后缀,二分出这一个为 \(0\) 的交点。判断的方法是该串在本质不同的子串中的降序排名是否等于该串的权值。查询一个串的排名:首先,预处理出所有本质不同的串的个数。这个值是 \(\sum n - SA[i] - height[i] +1\)。然后可以考虑将所有的子串排名(降序),一定是后缀---子串,后缀 --- 子串,且子串一定是前面的第一个后缀的前缀。所以也可以处理出每个后缀的真实排名(用上一个+当前后缀的独立前缀)。找一个子串的排名要找到它在后缀排序(降序)后出现的第一个位置,二分找到这个后缀,那么可以用上一个的排名 + 当前串中比自己更大的串计算出这个子串的排名。
洛谷3676 小清新数据结构
强者题解QAQ 以下\(Sum\)均表示整棵树的点权和。
1.动态点分治做法:可以先考虑不带平方。那么分别考虑每个点对答案的贡献为 \((dis_{u} + 1) * val_{u}\)。用动态点分治即可维护。用这个不带平方的式子可以构造出包含带平方的式子,因为无论以谁为根 \(\sum_{i = 1}^{n} s_{i} * (Sum - s_{i})\) 都是一个定值。我们可以维护这个的值以及 \(\sum_{i = 1}^{n} s_{i} * Sum\),就可以解出 \(\sum_{i = 1}^{n} s_{i} ^ {2}\)。
2.树链剖分做法:同样是构造答案。考虑把子树映射到树链上,就是支持维护区间平方和的线段树,拆平方分别维护可以做到。换根:如果当前根是 \(P\),那么只有 \(P\) 到 \(1\) 路径上的点会受到影响。假如这条路径上的点为:\(u_{0}, u_{1}...u_{k}\)(其中\(u_{0}\)为 \(1\)),记 \(a_{x}, b_{x}\) 分别表示以 \(1, P\) 为根时 \(u_{x}\) 的子树和,我们有 \(a_{i + 1} + b_{i} = Sum\) 的恒等式。利用这个式子我们就可以消元把贡献独立出来了。
**利用各类恒等式表示出所要式子,转化为求其他的东西而不是直接求解。
3.07 - T1 Substring
用后缀数组 + 单调栈,头铁化式……
3.07 - T2 Game
博弈论结论:一个组合游戏的SG值是所有后继游戏SG值的 mex,而一个游戏的SG值为组合游戏的异或和。可以发现这里每个点的后继状态其实是一个集合的任意子集,我们就是要求出这些数异或所不能得到的最小正整数。用线性基就是找到最小的没有值的位置在哪里(所以SG值一定会是\(2\)的幂次)。
AGC#017 C-Snuke and Spells
神仙思路:如果权值为 \(i\) 的点一共有 \(cnt_{i}\) 个,那么可以看作是覆盖了 \((i - cnt_{i}, i)\) 的这条线段。当线段覆盖了 \((0, n)\) 的时候,不需要操作就可以完成,否则最少的步数是空着的位置数。证明:把一个点的权值从 \(x\) 变成 \(y\) 会使一条线段的覆盖长度减少\(1\),另一条线段的覆盖长度增加 \(1\)。所以这是可行且最少的操作次数。
CF625E Frog Fights
一个青蛙每次如果撞到另一只青蛙,那么必然是与它相邻的下一只。这样我们维护一下相邻两只青蛙碰撞的时间,每次取出最早的一次碰撞来更新直到所有的青蛙均不能发生碰撞。用 set 来维护这个过程。
Bzoj3648 寝室管理
环套树的问题,先找到环并断掉一条边,统计出不经过这条边的路径总数。然后再对于环上的每个点所连出的子树再统计一遍,two pointer 能够保证统计的时候确实是经过的最短的路径。
CF840E In a Trap
发现权值的最大值只有 \(2 ^ {16}\),从这个地方下手。对于点 \(u\) ,我们不断向上跳,选取 \(2^{s}\) 为一段。考虑固定一个点 \(u\) 向上分段,在这一段中,它们 dis 的前 \(s\) 个位置都是相同的,而后\(16 - s\) 个位置则是固定的一个值。那么让每一个数的权值为 \(v ^ x\) (\(x\)是那个固定的值),就只需要考虑前面的位数了。出于二进制贪心的思想,我们优先前面大的树,在 \(trie\) 上贪心出最大的值再取能获得这个前缀的前提下所能获得的最大后缀。由此可以预处理出 \(f[u][x]\) 表示第 \(u\) 个点向上的块中,当询问的前 \(s\) 位为 \(x\) 时的最大值。这样的复杂度是:预处理:1.\(2^{16 - s}*(16 - s)\) 遍历块内元素并建立trie;2.\(2^{s}*s\) 遍历所有可能的前缀取值再trie上找到最大值;询问:1.\(\frac{n}{2 ^ {16 - s}}\) 遍历所有的块 \(O(1)\) 出解,2.\(2 ^ {16 - s}\) 暴力扫不满的块求解。发现二者折中可以取得较优的复杂度,即 \(s\) 取 \(8\)。
ZJOI2011 营救皮卡丘
可以先用 Floyd 预处理出 \(dis[i][j]\) 表示从 \(i\) 走到 \(j\),其中经过的最大点不超过 \(j\) 的最短路。那么问题变成用 \(k\) 条不相交的链去覆盖所有的点一共有多少种方案。使用有源汇有上下界的最小费用可行流可以求解。
HAOI2013 SAO
转化题意:给定 \(n\) 个数,两两之间有先后的限制。其中限制条件形成一个树形图,求合法的拓扑序数量。直接 dp 设状态 \(f[i][j]\) 表示以 \(i\) 为根的子树中, \(i\) 的排名为 \(j\) 的方案数。加上前缀和优化可以 \(O(1)\) 转移,又由于转移的大小均为子树大小,所以是 \(n ^ {2}\) 的。
CF671D Roads in Yusland
定义状态 \(f[i]\) 为覆盖 \(i\) 所有子树内的边以及 \(i\) 到父亲的边的最小代价。暴力转移即为枚举一条终点在 \(i\) 上方,起点在 \(i\) 内部的链,代价为 \(w[i] + S\)(其中 \(w[i]\) 为这条链的代价, \(S\) 为所有这条链上的点的儿子的 \(f\) 之和(不包括在链上的儿子))。把所有的链按照终点的 \(dfs\) 序编号,那么一个点子树内部的链会对应线段树上一段连续的区间。可以在终点和起点分别加入 & 删除一条链,依次在线段树上更新每条链的代价。每次查询区间的最小值就是答案。