其他分享
首页 > 其他分享> > 【题解】CF1706C Qpwoeirut And The City

【题解】CF1706C Qpwoeirut And The City

作者:互联网

【题解】CF1706C Qpwoeirut And The City

题意简述

算法分析

首先考虑在什么情况下“凉爽的”建筑物是最多的。

由于“凉爽的”建筑的定义,我们知道不会存在连续的“凉爽”建筑。

由于第一座和最后一座建筑一定不是“凉爽的”,所以最终“凉爽的”建筑数为 \(\left\lceil \dfrac{n}{2} \right\rceil - 1\)。

事实上,这个结果实际上是分类讨论得出的:

  1. 若 \(n\) 为偶数,可知最多有 \(\dfrac{n-2}{2}\) 座建筑是“凉爽的”。
  2. 若 \(n\) 为奇数,可知最多有 \(\dfrac{n-2+1}{2}\) 座建筑是“凉爽的”。

这个结论过于显然,就不举例了。

下一步考虑应该令哪些建筑物是“凉爽的”。

对于 \(n\) 是奇数的情况,“凉爽的”建筑的位置是固定的。令这些位置的建筑的高度高于两侧建筑高度的最大值即可。

对于 \(n\) 为偶数的情况,情况会稍微复杂一些:

这里令 \(1\) 代表“凉爽的”建筑,令 \(0\) 代表非“凉爽的”建筑。

在纸上写一写就会发现,符合题意的序列并不是唯一的。

比如 \(n=8\) 时就有如下几种情况:

- 1 0 1 0 1 0 -
- 1 0 1 0 0 1 -
- 1 0 0 1 0 1 -
- 0 1 0 1 0 1 -

但是,通过观察这四个序列,我们能发现一些规律:

  1. 去掉第一项和最后一项,中间的每两个分成一组,每组一定是 1 00 1 其中之一。

  2. 对于这些组,一定是前一部分是 1 0 ,后一部分是 0 1 ,并且仅会在整个序列中间更改一次顺序。

    因为 \(1\) 的左右两边一定是 \(0\) ,所以 0 1 后面不能接 1 01 0 前面也不能是 0 1

所以我们可以事先求出全是 1 0 的花费前缀和,求出全是 0 1 的花费后缀和,最后枚举在第 \(k\) 组改变了顺序求最小值即可。

对于每个测试用例,复杂度为 \(O(n)\)。

参考代码

#include <bits/stdc++.h>
using namespace std;

const int maxN = 2e5;
typedef long long ll;

int B[maxN];
//一定别忘了开long long
ll A1[maxN];
ll A2[maxN];

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        int N;
        scanf("%d",&N);
        for(int i = 1;i<=N;i++) scanf("%d",&B[i]);
        ll ans = 0;
        if(N & 1){ // N为奇数
            for(int i = 2;i<N;i+=2){
                int M = max(B[i-1],B[i+1]);
                if(B[i] <= M){
                    ans += (M+1-B[i]);
                }
            }
        }else{
            memset(A1,0ll,sizeof(A1));
            memset(A2,0ll,sizeof(A2));
            
            int cnt = 1;//第 cnt 组
            for(int i = 2;i<N-1;i+=2){
                int M = max(B[i-1],B[i+1]);
                if(B[i] <= M){
                    A1[cnt] = A1[cnt-1] + (M+1-B[i]);
                }else{
                    A1[cnt] = A1[cnt-1];
                }//求情况1增高的前缀和
                cnt++;
            }
            cnt = (N>>1)-1;
            for(int i = N-1;i>2;i-=2){
                int M = max(B[i-1],B[i+1]);
                if(B[i] <= M){
                    A2[cnt] = A2[cnt+1] + (M+1-B[i]);
                }else{
                    A2[cnt] = A2[cnt+1];
                }//求情况2增高的后缀和
                cnt--;
            }
            int r = (N >> 1);//一共有 (N/2)-1 组,但是考虑到下面的循环边界就加了一
            ans = 1e17;//最大值要足够大。。。
            for(int i = 1;i<=r;i++){
                //枚举在哪组变序
                ans = min(ans,A1[i-1]+A2[i]);
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

标签:凉爽,int,题解,long,建筑,leq,CF1706C,maxN,Qpwoeirut
来源: https://www.cnblogs.com/burnling/p/16496072.html