| 题目传送门 题目描述的很清晰,图都配了,就不赘述题面了。
 思路分析
 
 问题一:求最小紧凑性
 
 首先可以很容易发现,紧凑性便是以横坐标最大和最小的两个摄像头画面的横轴距离为长、以纵坐标最小和最大的两个摄像头画面的纵轴距离为宽的矩形面积,所以我们只需要让两者尽可能小就行了。
 显然,左右的移动和上下移动的这两类操作对于最终答案的贡献是分开的,两者不会互相干扰。以题目第二组样例为例,如图,蓝色部分即为摄像头画面:
 
 对于此时的图像画面而言,紧凑性为 \(4\times3=12\) 。
 执行左移操作,则画面变更为:
 
 紧凑性变为 \(2\times3=6\) 。
 对于以上左移操作,出现变化的只有横坐标最大和最小的两个摄像头画面的横轴距离,而纵向并没有受到左移操作的影响。同理,上下移动操作也不会影响到横向,所以我们可以放心大胆地把横向和纵向分开讨论。
 仍以题目第二组样例为例:
 先来看横向的。既然我们要求的是横坐标最大和最小的两个摄像头画面的横轴距离,那我们不妨先给所有横坐标进行排序,我们便得到了这么一个序列 \(a\):
 
 对应到图中,则变成了这样:
 
 (tips:重复的元素其实无所谓,实际代码中去不去重不影响判断)
 设最终答案的横长为 \(X\) 不难发现,当且仅当有元素从一个端点移动到另一个端点时 \(X\) 才会发生变化,其余步骤移动均不会改变 \(X\) 的值。
 而从一个端点移动到另一个端点这一步骤,我们既能通过左移来实现,也能通过右移来实现。具体地,如下图,如果我想把左边的画面移动到最右边,既可以通过左移一步来达成,也可以通过右移三步来达成,而其他的画面的位置会跟随其一并发生变化,移动的方式最终不会影响到 \(X\) 的值。
 
 所以先抛开右移操作,仅考虑左移:发生左右端点间的移动,便是把 \(a\) 中的值最小的点的值变化为 \(h\) ,其余的点的值则减去最小值。由于我们已经给 \(a\) 排好序了,所以其中的最小值便是 \(a_1\) 了,经过左移到左端点后再进行一次左移的操作后,序列 \(a\) 就会变成 $ h,a_2 - a_1 ,\cdots, a_k - a_1$ 。我们再对其排一次序,得到 $ a_2 - a_1 ,\cdots, a_k - a_1,h$
 此时,我们再代入求 \(X\) 的公式,便会得到 \(X=h-(a_2-a_1)+1\)。而如果把现在的序列 \(a\) 再进行一次将最小值移动到右端点的操作,我们又能得到一个新的 \(X\) 。可以发现,一共存在 \(K\) 种可能的 \(X\) ,推到以下可得:\(X_i=h-(a_i-a_i-1)+1\ (\ 1 < i \leq k)\) 其中,\(X_i\) 表示以原数组 \(a\) 的第 \(i\) 个数作为最小值时 \(X\) 的值。
 带入到样例中,我们能得到如下图所示的序列 \(X\) :
 
 欸?那 \(X_1\) 怎么办呢?我们只需要在最开始给 \(a\) 排好序的时候直接 \(a_k-a_1\) 就好啦,因为 \(a_1\) 本来就是这么多节点横坐标的最小值嘛:
 
 于是这样,我们就得到了所有可能的 \(X\) 。
 相信这时候就有聪明的同学会想到,题目要求的明明是最小值的紧凑性,那我直接维护最小的 \(X\) 不就行了吗?费这个空间把所有 \(X\) 存下来干嘛?
 没错,我们在枚举所有的 \(X\) 时仅需要维护最小的那个就可以了,没必要保留其他那些没什么用处的数据:
 
 纵向上同理,设最终答案的纵长为 \(Y\) ,同相同的方法挨个枚举可能的 \(Y\) 并记录最小值就行。这样我们就解决了第一个问题。
 问题二:达成最小紧凑性时的步数
 
 别忘了题目还有一个问题呢!
 前面我们在求最小紧凑性的时候,已经锁定了最小的 \(X\) 和 \(Y\) 的值,并且在枚举两者的时候找到了它们对应的点的坐标位置,那我们不妨在枚举的同时再额外考虑一下如何到达这个问题。
 依旧以样例二、横向操作为例:
 前文提到,“ 从一个端点移动到另一个端点这一步骤,我们既能通过左移来实现,也能通过右移来实现 ”,具体地,想让数组 \(a\) 中的最小值成为最大值,可以通过将其左移到左界并再次左移,或者是将其一直右移直至右界:
 
 (素材复用)
 但仅仅只有这两种方法了吗?并不一定。
 仔细思考可以发现,对于每个 \(X_i\) ,枚举时我们的目的仅仅只是让最左端点移动成为数组 \(a\) 中的最大值,而不一定是让它成为右界 \(h\) 。
 样例二并不能很好地体现这一点,我们换一张图:
 
 显然,我们在考虑最左边的 \(a_1\) 右移成为最大值时,其实只需要右移两次、把 \(a_2\) 右移超过右界来到左界就可以了,并不需要把 \(a_1\) 移动到最右端:
 
 所以 让最左端点移动成为数组 \(a\) 中的最大值 这个问题也可以转变为 让最左端点右侧的第一个端点移动成为数组 \(a\) 中的最小值。
 面对转换后的问题,最简单的方式不就是把 \(a_2\) 这家伙给弄到左端点的位置上去吗?而这又有了左移和右移两种方法。
 于是,我们可以得到,对于每个 \(X_i\) ,最简单地达成它一共有四种方式,即四种移动步骤:
 1.将 \(a_i\) 左移至左端点的位置再左移一次,步数: \(a_i\) ;
 2.将 \(a_i\) 右移至右端点的位置,步数: \(h-a_i\) ;
 3.将 \(a_{i+1}\) 左移至左端点的位置,步数: \(a_{i+1}-1\) ;
 4.将 \(a_{i+1}\) 右移至右端点的位置再右移一次,步数: \(h-a_{i-1}+1\)
 由于题目需要的是最小步数,所以我们就取这四个值里头最小的那个作为 \(X_i\) 对应的步数就可以啦!
 纵向也是一个道理,最后输出答案的时候输出最小的 \(X\) 和最小的 \(Y\) 相乘的结果和他们对应的最小步数相加就完工啦!
 恭喜你切了这道题!
 最后,进点食:
 十年OI________,不开________见祖宗!
 Code
 
 [code]#includeusing namespace std;const int MAXK=1e5+5;#define int long longint h,w,k,x[MAXK],y[MAXK];      //x[]对应横坐标,即文中的a,y[]对应纵坐标int min_x,min_y,min_stepx=0,min_stepy=0;    //min_x、min_y分别是最小的X和最小的Y;min_stepx和min_stepy则分别对应X和Y最小时的步数signed main(){        cin>>h>>w>>k;        for(int i=1;i>x>>y;        if(k==1)                //这里加了个特判,因为就一个点的时候答案是一定的,再跑一遍程序浪费时间,其实加不加无所谓        {                cout
 |