AGC066 题解
这次终于不咕了!
A
将网格黑白染色,\(i+j\) 为奇数/偶数 标为 黑色/白色。
将黑色格变为 \(a_{i,j}\bmod 2d = 0\),白色格变为 \(a_{i,j}\bmod 2d = d\)。这样代价上界为 \(n^2d\),即把 \(x\) 移向一个 \(2d\) 长度的区间的端点。
但是这样的“期望代价”是 \(\frac{1}{2}n^2d\) 的。考虑枚举 \(x\),将黑色格变为 \(a_{i,j}\bmod 2d = x\),白色格变为 \(a_{i,j}\bmod 2d = d+x\),根据鸽巢原理,一定有一种方案代价在 \(\frac{1}{2}n^2d\) 之内。
题外话:赛时一开始就想到了这个做法,但以为是 \(n^2d\) 的就否定了..
B
通过打表比较优的情况可以发现,优秀的情况末尾都有一串 \(0\)。考虑构造一个数,使得每次 \(\times 2\),末尾会变成 \(0\)。
那问题转化为:构造一个奇数,使它在 \(n\) 次内,每次 \(\times 5\) 数位和递增,然后构造 \(x\times 5^n\) 即可。
比如 \(3\to 15\to 75\to 425\) 递增,则可以构造 \(425\to 750\to 1500\to 3000\)。
但如果随便取一个奇数 \(1,3\),在若干次 \(\times 5\) 后就会有一次不递增的...
但是我们可以把一堆数乘 \(5^{50}\) 拼起来(比如取 \([1,100]\)),并在它们之间加一串 0 使得它们互不影响。然后发现这样就递增了!因为整体的趋势是递增的,将大量的数拼起来消去了小量的递减影响。
C
考虑如何判定一个 AB
串是可以消空的,称能消空为合法串。
手玩样例会发现,直接贪心消是不行的,比如 BAAABA -> ABA
,BAAABA -> BAA
。
考虑一个区间 dp,设 \(dp(l,r)\) 表示能否消空 \([l,r]\)。有两种转移:
- 枚举从 \(k\) 断开,判断能否消空 \([l,k],[k+1,r]\).
- 若 \(s_l\ne s_r\),枚举 \(s_k = \text{A}\),判断能否消空 \([l+1,k-1],[k+1,r-1]\),然后将 \((s_l,s_k,s_r)\) 一起消。
然后进行 dp,设 \(f_i\) 表示前 \(i\) 个字符最少消成几个字符。有转移:
- \(f_i + 1 \to f_{i+1}\)
- 若 \(dp(i,j)=1\):\(f_i\to f_j\)
如果一个区间 \((i,j)\) 能从中间断开来消空,则自然可以不考虑它。考虑不可断开的合法串有什么性质。
可以得出不可断开的合法串的一些必要条件:
- 区间内 \(\text{A}\) 的个数为 \(\text{B}\) 的两倍。
- \(s_l\ne s_r\)。
surprisingly 根据打表 合法串/不合法串 的结果,这也是充要条件!具体的证明是:假设我们不删头尾的 A,B,中间共有 \(2n-1\) 个 \(\text{A}\) 和 \(n-1\) 个 \(\text{B}\)。相当于 \(2n-1\) 个 \(\text{A}\) 放进 \(n\) 个空隙,根据鸽巢原理,中间一定有一个 \(\text{B}\) 旁边有两个 \(\text{A}\)。
设 \(sum_i\) 表示前 \(i\) 个位置中 \(2\times count_A-count_B\),则只有 \(sum_{l-1}=sum_r\) 且 \(s_l\ne s_r\) 时可以转移。
记录前缀中 \(sum=x,s=y\) 的最小 \(f\),然后就可以 \(O(n)\) dp 了。Submission
D
每个移动的代价都是正的,考虑最终移动完的最优结果是怎样的。
假设只有一连串的 A
,移动完后一定会变成 ABABABA
,只是 AB
串从哪个位置开始需要确定,而开始的位置是 \(O(n)\) 个。
假设有两串 A
,移动完后的结果可能是两个 AB
串;或者相向移动,合起来变成一个大的 AB
串。
经过类似的考虑发现,最优的移动是:把一开始的 A
连续段切分成左右(也可能不切),再把若干个 A
连续段合在一起,变成一个 ABAB
串。
可以发现,上述的移动可以概括为:将一个 \(AB\) 个数相等的区间变成 ABABAB..
或 BABABA..
。
那么这样的移动只有 \(O(n)\) 种,只需要处理 \(r_i\) 表示 \([i,r_i]\) 是 \(AB\) 个数相等的。每次移动的代价也是固定的,因为把这个区间变成 ABABAB
或 BABABA
的话 A
的移动方向都是相同的,可以前缀和后 \(O(1)\) 计算。
设 \(f_{i,0/1}\) 表示操作完前 \(i\) 个字符,最后一个字符是 \(B/A\) 的最小代价。转移只需要枚举下一个操作区间 \([i,r_i]\) 变成 ABAB
还是 BABA
,或者第 \(i\) 个字符不操作,复杂度 \(O(n)\)。Submission
F
怎么又把 3 Letters trick 拿出来。属于是可做,但需要大量时间手玩和推细节的题。。
考虑把 ABC
串转为一条折线:\(A\to B,B\to C,C\to A\) 则为 +
,否则为 -
。
则如果 swap 位置非头和尾,则体现为 +++
和 ---
相互转化。
如果 swap 尾部,则为尾部 ++
和 --
相互转化;如果 swap 头部,则头部字母会变化,且头部 ++
和 --
相互转化,如 A++
\(\to\) B--
。
那考虑折线的“最简形式”:首先将连着的 +++
,---
消掉,它们可以插在串的任意位置;接着,当头部/尾部存在 两个相同 加 一个相反 时,可以把这三个字符消掉。如果这样转化完后,折线长度没有减少,说明这个串根本无法操作,直接返回。
接下来讨论一些 corner case 来最小化头部字母,把头部字母变成 A
。
然后考虑贪心:
- [1] 假设原折线的下一步走到 \(c_1\),反着走走到 \(c_2\)。如果 \(c_2<c_1\) 且有可以使用的
+++/---
,则塞一个+++/---
进来改变方向,否则按原方向走。 - [2] 如果原折线没有下一步了,则贪心塞一个
+++/---
往更优的方向走。
但是这样的贪心只塞了一些 +++/---
,并没有考虑改头部和改尾部。
考虑改头部的影响:A
\(\to\) B--+
\(\to\) C--+--+
\(\to\) A--+--+--+
。发现这个方案是更劣的,可以不考虑更改头部。
考虑改尾部的影响:由于前面简化了折线,所以尾部最后一个连续段只有一个相同的 +/-
。只有在尾部添加 +++
时,才可能(使用尾部操作)变成 +--
。
再考虑贪心的整个过程:
- 在上述 [2] 时才可能在尾部添加。
- 如果在尾部添加了,则前面的串中一定不会出现
C
,如果前面要走到C
肯定在前面添加了。 - 手玩贪心,在尾部添加的最优串会形如:
A
:(+(-(+(..)++)--)++)
,B
:(-(+(-(..)--)++)--)
,改末尾最多只能翻转最后两个字符。于是特判一下就行了。
写起来有点大模拟 + 细节。