Atcoder 倒刷计划
AGC#30 D
题意:有一个长度为 \(N(\leq 3000)\) 的序列。有 \(Q(\leq 3000)\) 个操作 \((x_i,y_i)\)。每个操作可以选择是否执行;若执行,则交换 \(A_{x_i}\) 和 \(A_{y_i}\)。一共有 \(2^Q\) 种选择方法。问所有选择方法最终序列里的逆序对数量之和是多少。模一个大质数。
题解:这题容易陷入思维僵局。比如先枚举某一个位置 \(k\),然后设 \(f_{i,j}\) 表示到第 \(i\) 个操作,我们关注的那个数字现在在 \(j\) 的期望/总方案数。最后枚举两个数合成,总复杂度是 \(O(N^2Q)\)。其实每次操作很“稀疏”(只和两个位置有关),但是这种方法却必须维护好所有位置。
标准做法是,设 \(f_{t,i,j}\) 表示进行了 \(t\) 轮后,当前第 \(i\) 个位置的数字大于第 \(j\) 个的概率。每次转移时发现,只有其中一个数字是 \(x_i\) 或 \(y_i\) 的位置 \((i,j)\) 才会被修改,别的直接继承(这也是为什么要用概率来表示,因为概率是直接继承,方案数要集体乘 \(2\))。每次修改的状态数只有 \(O(N)\) 个,所以总复杂度降为 \(O(NQ)\)。
AGC#30 E
题意:给出两个长度为 \(N(\leq 5000)\) 的 \(01\) 序列 \(s\) 和 \(t\),保证它们其中任意三个连续数字不可能全相同。每次可以翻转 \(s\) 中的一位,但必须实时满足这一限制。问最少几步可以把 \(s\) 变为 \(t\)。
题解:刚开始感觉可以DP,记一下前几位数字怎么选,从左到右dp过去。后来感觉应该将 \(01\) 序列划成一段段的,不能无脑DP。
题解的解释十分形象。我们在所有 \(01\) 交界处都划上线(为了后续分析的方便,开头前和结尾处还要花上无穷多的线)。由实时的限制我们知道,中间任意两条线直接的距离必然是 \(1\) 或 \(2\)。每次翻转一位 \(01\),相当于将一根线向左/右移动。假设我们知道了 \(s\) 和 \(t\) 串线的一一对应关系,可以证明,移动步数的下界(\(\sum |pos_i-pos_j|\))必然能取到,这样我们只需 \(O(N)\) 扫一遍即出解。因为线是 \(O(N)\) 条,所以最多只会有 \(O(N)\) 种有效的对应关系,直接枚举即可。*线的对应关系好像还存在三分性,可以进一步优化速度。