AGC037 题解
这篇写的跨度有点太长了不记得当时的想法
[AGC037A] Dividing a String
题意
给定一个字符串 \(S\),请你找出一个最大的 \(k\),使得将这个字符串划分成 \(k\) 段后能够保证相邻的两段不相同。
\(1\le |S| \le 2\times 10^5\),且保证 \(S\) 串内均为小写字母。
idea
简单 \(dp\),考虑段长 \(1\),\(2\) 交替分割一定满足题意,设 \(f_{i,0/1}\) 表示当前考虑到第 \(i\) 位,第 \(i\) 位属于的段长是 \(1/2\),转移时符合条件即可。
[AGC037B] RGB Balls
题意
给出一个只包含 \(R,G,B\) 的字符串,保证它们三种字符出现的次数都为\(n\),现在你要将这 \(3n\) 个字符分给 \(n\) 个人,使得每个人都拿到了三种字符,假设某人的三个字符在序列中的位置为 \(p_1,p_2,p_3\),其中 \(p_1≤p_2≤p_3\),那么这个人的贡献为 \(p_3-p_1\),问使得总贡献最小的方案数有多少,答案对\(998244353\)取模。
\(1 \leq n \leq 10^5\)。
idea
考虑先最小化答案,感性理解,同一人的所有字符离得越近越优,即对于每个前缀新加入一个字符,优先给配对了两种字符的人贡献,其次给配对了一种字符的人贡献,最后在分配给新的一人。
于是发现 \(p_3-p_1\) 的贡献,可以在独自开一组时 \(-p_1\),在填最后一个字符时\(+p_3\),贡献可以分离,例如当前位置是 \(R\),给前面任意组合 \(BG\) (或 \(GB\))贡献相同,可以利用这点统计答案。
于是记 \(r,g,b,rg,rb,gb\) 表示对应组合的个数,利用上述方法转移即可。这样会不会因为如 \(R\) 不知道贡献给单独的 \(G\) 还是单独的 \(B\) 而出问题?事实上,这样会形成 \(gb\) 所以不会出现。
这样的做法钦定了按编号顺序从小到大匹配,最终答案需要乘 \(n!\)。
[AGC037C] Numbers on a Circle
题意
一个环上有 \(n\) 个正整数,一次操作可以令 \(A_i\leftarrow A_{i-1}+A_i+A_{i+1}\),求多少次操作可以使 \(A\) 变成 \(B\),无解输出 \(-1\)。
\(1 \leq n \leq 2\times10^5\)。
idea
加法的可能性太多,随随便便就超过限制了,考虑倒着对 \(B\) 进行减操作,由于原序列最后操作的元素会比较大,为了防止减成负数,我们应该对每个极大值点,即 \(B_i>B_{i-1}+B_{i+1}\) 这样的 \(i\) 优先操作,对于所有符合题意的 \(i\) ,不妨设一堆相邻的极大值点一个为 \(i_1\),另一个为 \(i_2\),其满足 \(|i_2-i_1|+1\ge3\),这也就是说 ,对 \(i_1\) 操作不会使 $i_2 $变成非极大值点,于是乎所有极大值点无关操作顺序。
考虑每次如何快速求出一个极大值点,显然的,序列的最大值一定是一个极大值点,于是可以用优先队列维护,每次取出最大值进行操作直到该位置非极大值点,或已经 \(\le A_i\),每次每个数至少减少一半,这是因为如果 \(2(B_{i-1}+B_{i+1})< B_i\),减若干次后 $ B_i'<B_{i-1}+B_{i+1}$,如果 \(2(B_{i-1}+B_{i+1})\ge B_i\),减一次后 $ 2B_i'\ge B_i$,于是复杂度为 \(O(n\log n\log V)\)
[AGC037D] Sorting a Grid
题意
一个 \(n\times m\) 的矩阵 \(A\),元素为 \(1\) 到 \(n\times m\) 的排列。
- 将 \(A\) 每一行的元素任意排列得到 \(B\)。
- 将 \(B\) 每一列的元素任意排列得到 \(C\)。
- 将 \(C\) 每一行的元素任意排列得到 \(D\)。
要求 \(D_{i,j}=(i-1)\times m+j\) , 请输出一组合法的 \(B, C\).
\(1\le n,m\le 100\)
idea
如果给 \(D\) 每行染一种颜色的话,需要满足以下条件:
- \(C\) 中每行颜色相同。
- \(B\) 中每列包含 \(n\) 种颜色。
于是每种颜色对所在的行建边,考虑对每列跑一边二分图匹配即可构造。
[AGC037E] Reversing and Concatenating
题意
给定长度为 \(n\) 小写字母字符串 \(s\) 和正整数 \(k\),求进行 \(k\) 次如下操作后字典序最小的 \(s\) :
- 将 \(s\) 和 \(s\) 的翻转拼接得到 \(t\) , 从 \(t\) 中截取长度为 \(n\) 的子串作为新的 \(s\).
\(n\leqslant 5000,k\leqslant 10^9\)
idea
很有意思的题。
考虑 \(k=1\),最优策略不必多说复制一遍枚举找最短的即可。
记 \(s\) 的最小值为 \(c\),其中的最长连续段长度为 \(l\),我们的策略肯定是要使 \(l\) 尽可能被复制,但是第一次 \(l\) 可能不在末尾,这很不好操作,于是我们先强制操作一次变成长度为 \(2n\) 的字符串 \(t\),找一次操作后最适合操作的子串再进行操作。
使 \(c\) 和 \(l\) 成为 \(t\) 的最小值和最长连续长度,我们发现一次操作使 \(l\) 乘 \(2\),于是我们最后有 \(\min(2^{k-1}l,n)\) 个 \(c\)。
对于 \(2^{k-1}l<n\) 的情况,使剩下的 \(n-2^{k-1}l\) 的字典序最小。回顾我们的操作过程,发现每次的串形如这样:\(t=\overline{xyzcccczyx}\),最后一次操作会取得是:\(s=\overline{ccccz}\) 这样的形式,其实是选择的长度为 \(l\) 的区间 \([x,x+l-1]\) 之前的一段后缀,我们只需要翻转 \(t\) 把所有长为 \(l\) 的 \(c\) 段的最小后缀,暴力去找即可。
[AGC037F] Counting of Subarrays
题意
给定 \(l\),连续至少 \(l\) 个相同的数 \(k\) 可以合并成 \(1\) 个 \(k+1\)。
给定一个长度为 \(n\) 的序列,问该序列有多少个子区间可以通过若干次合并变成 \(1\) 个数。
idea
构式题。
考虑判断一个区间是否合法,记 \(w\) 为一个区间的最大值:
- 区间只有一个数,该区间属于级别 \((w,l)\)。
- 区间只有 \(w\),且 \(w\) 的数量 \(\ge l\),该区间属于 \((w+1,l)\)。
第一种情况答案就是 \(n\),对于第二种情况,注意到一个区间属于的级别只和最大值有关,对于 \(<w\),只有尽可能的合成,才可能会产生贡献。
于是我们初步的思想便有了,按从小到大的顺序,每次取出一段值为 \(w\) 极长连续区间进行计算,计算完毕后,如果可以合成 \(w+1\) 就塞回去,否则删掉即可。
考虑如何计算的问题,我们对序列的每个位置维护其成为左端点和右端点的方案数,对于区间 \([1,k]\),考虑左端点在 \(1\),\([1,l-1]\) 无法成为右端点,\([l,2l-1]\) 可以成为第一个右端点,依次类推即可。
但是这样还没有完,对于第 \(l\) 个右端点,这些区间会被 \(x\) 统计一次,合并后还会被 \(x+1\) 再统计一次,我们需要容斥掉这些多余的方案数。
计算完成后如何合并的区间 \(<L\) 我们就将这段区间删除,用链表维护即可。
本文作者:yshpdyt
本文链接:https://www.cnblogs.com/yshpdyt/p/18435662
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步