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\) 个数相等的。每次移动的代价也是固定的,因为把这个区间变成 ABABABBABABA 的话 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:(-(+(-(..)--)++)--),改末尾最多只能翻转最后两个字符。于是特判一下就行了。

写起来有点大模拟 + 细节。

posted @ 2024-04-03 15:51  Rainbow_qwq  阅读(130)  评论(0编辑  收藏  举报