「基础算法」贪心 ——“推平”法

注:这个算法本质上是一个贪心技巧,而且命名由作者自拟,读者可以根据自身理解来为算法命名。

问题引入

一道耳熟能详的问题:硬币翻转。

题意如下:

  • 有 $n$ 个硬币按顺序摆在桌上,每个硬币可能是正面朝上 $(a_i=1)$,也有可能是反面朝上 $(a_i=2)$。
  • 每次选取连续的 $k$ 个硬币,将它们翻转。
  • 问最少翻转多少次可以将所有硬币变成正面朝上,如果不可能实现输出 $-1$。
  • $1 le k le n le 5 imes 10^6$,$a_i in {1,2}$。

简单分析

我们可以先观察一下题目。

容易发现,如果两次翻转的是同一个区间的硬币,那么正面朝上的硬币还是正面朝上的硬币(反面同理),故没有效果。

所以,如果可以实现目的,翻转的硬币区间一定是不同的。

那一个长度为 $n$ 的序列选出长度为 $k$ 的子串,最多只有 $n-k+1$ 个不同的方案,而且翻转操作不会应操作的顺序受到影响

于是这道题,可做了。

何为推平

这 $n-k+1$ 个子区间如果乱选,时间复杂度极高,为 $O(2^{n-k+1} imes nk)$。

这时我们就应该找到一个突破口。

如果我们要翻转 $1$ 号硬币,那只能翻转区间 $[1,k]$,然后 $1$ 号硬币归位;

然后如果这时 $2$ 号硬币原来是正的,被翻转一次后变反了,因为不能修改同一个子区间,我们只能把区间 $[2,k+1]$ 翻转。

……以此类推。

最后,如果有解,答案一定是执行翻转操作的次数。

正确性

正确性其实已经很明显了,因为如果 $1$ 号硬币至 $b$($b$ 是一个 $[1,n]$ 间的整数)都是正面,再将它们反转一定不是最优的。

所以,这个做法在每一个环节都是最优的。

算法优化

上述做法还是 $O(n^2)$ 的,如何优化?

其实看到翻转操作,就应该知道这么做了。

将区间内所有正变反,反变正,明显是区间异或操作,因为没有修改,所以可以用差分解决。

时间复杂度降为 $O(n)$。

何时无解

注意到,这题可能存在无解的情况。

那这就很容易了,如果翻转到第 $n-k+1$ 个子区间(就是最后一个区间)后还没有把所有硬币变成正的,这时就会无解。

推荐题目

洛谷OJ P6070 『MdOI R1』Decrease

原文地址:https://www.cnblogs.com/zengpeichen/p/13765934.html