Codeforces1474D. Cleaning(前缀和/思维)

Codeforces Round #696 (Div. 2) 全文见:https://blog.csdn.net/qq_43461168/article/details/112856420

D. Cleaning

题意:一个数组。每次可以选择两个相邻的数,同时减小1。而且允许交换两个数,最多操作一次。问是否能最后全变成0。

思路:前后缀和。第一个数,肯定是和第二个数一起减。并且减到0的。同理第二个数还要和第三个数一起减。那么从左往右这样可以一直减下去。就变成了一个,a1,a2-a1,a3-a2+a1…这样的数组。存起来作为前缀和pre[],如果pre[n] == 0 则说明,减到最后大家都是0了。已经满足题意了,可以提前结束。同理,从右往左也这样进行一次。存起来作为后缀和suf[]。要保证数组都是非负数,不合法的可以进行标记。然后可以想到,如果 pre[i] == suf[i+1],那么这两个数相等。再一减。不就全变成0了嘛。因为从左往右的都清零了。从右往左也清零了。就剩这两个独苗。如果他们相等显然就全清零了。这是不交换的状态。如果交换两个数呢。如图。如果要交换的元素是a[i] 和 a[i-1],那么受到影响的就是pre[i] 和 suf[i+1]的值。具体来说,就是pre[i] = a[i+1]-pre[i-1] , suf[i+1] = a[i] - suf[i+2]。如果现在这两个值相等。也就是 pre[i] == suf[i+1],则说明交换之后,满足清零的条件了!输出YES。如果所有位置都枚举了一遍。还是不行,那就是真的不行了。输出NO。

AC代码:

#include <iostream>
#include <bits/stdc++.h>
#define int long long
#define mk make_pair
#define gcd __gcd
using namespace std;
const double eps = 1e-10;
const int mod = 1e9+7;
const int N = 3e5+7;
int n,m,k,t = 1,cas = 1;
int a[N],b[N];
int sel = 0;
int pre[N];
int suf[N];
 
signed main(){
    cin>>t;
    while(t--){
        cin>>n;
        for(int i = 1 ; i <= n ;i ++)
            cin>>a[i];
        for(int i=  1; i <= n ; i ++){
            if(pre[i-1] == -1 || a[i] < pre[i-1]){
                pre[i] = -1;
            }else{
                pre[i] = a[i]-pre[i-1];
            }
        }
        suf[n+1] = 0;
        for(int i = n ; i >= 1; i --){
            if(suf[i+1] == -1 || a[i] < suf[i+1]){
                suf[i] = -1;
            }else{
                suf[i] = a[i]-suf[i+1];
            }
        }
        int res = 0;
        if(pre[n] == 0) res = 1;
        for(int i = 1; i < n ; i ++){
            if(pre[i-1] == -1 || suf[i+2] == -1) continue;
            else{  // swap a[i] with a[i-1]
                if(a[i] >= suf[i+2] && a[i+1] >= pre[i-1] &&
                   a[i+1]-pre[i-1] == a[i]-suf[i+2]){
                    res = 1;break;
                }
            }
        }
        puts(res ? "YES" : "NO");
        cas++;
    }
 
}
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 1024 设计师:白松林 返回首页