CF1875E-DP状态设计
论 DP 状态设计:
问题描述:
给定一个 \(01\) 串,每次可以交换相邻的 \(0\) 和 \(1\) 。问 \(k\) 次操作过后所有可能的状态有多少。
\(n\le1500 ,k\le1500\)
一. 简单转化
对于这种多种操作方案却可能对应同一个结果的问题,肯定要去考虑某一种方案合不合法。
那么什么样的最终序列是合法的呢?
显然,由于相邻两个 \(1\) 的相对位置无法发生变化,设某个 \(1\) 操作完后相对于原来的位移为 \(dis_i\) ,所以合法需要满足:
-
\(\sum_{}dis_i\le k\)
-
\(\sum dis_i≡k (mod\ 2)\)
那么就是显而易见的 \(dp\) 。且位移和肯定要算到一个状态里。
二. 论两种 DP 方式:
1. dp[第i个1][目标位置j][花费t]
这样可以很容易地写出转移,然后前缀和优化至 \(O(n^3)\) ,极限卡常可以过。
2. dp[扫描位置i][前缀差d][花费s]
前缀差 \(d\) 表示当前前缀中实际的 \(1\) 的个数与给定 \(01\) 串中的个数的差。
假设现在扫描到第 \(i\) 个位置,初始串这一位的值是 \(a_i\) (0 或 1)。
我们枚举目标串这一位 \(x\)(\(x = 0\) 或 \(x = 1\))。
- 计算新前缀差:
(解释:新前缀差 = 旧前缀差 + 目标值 - 初始值)
- 计算新累计代价:
(为什么加 \(|nd|\)?因为 \(|nd|\) 就是跨越当前边界 \(i\) 和 \(i + 1\) 的 '1' 的数量,每跨越一个 '1' 都要消耗一次交换操作)
- 转移方程:
这一步也是非常的妙哉,然后这样不加前缀和优化都能实现 \(O(n^3)\)
- 关键发现:
\(d\) 的范围是 \([-\sqrt{k},\sqrt{k}]\) 。
这是因为有 \(d\) 个 \(1\) 需要跨过中线,而这样的代价至少是 \(1+2+...+d\) 那么由于总代价不超过 \(k\) ,所以 \(d\in[-\sqrt{k},\sqrt{k}]\) 。
三. 差别:
关注移动与关注有无,与其关注某一个 \(1\) 最终移动到了那里,不如去关注最终某个位置有没有 \(1\) 。
当然,这两种思考方式都很重要。但本题后者显然更优。

浙公网安备 33010602011771号