Codeforces#681 (div.2)D. Extreme Subtraction(差分序列,构造)
D. Extreme Subtraction
time limit per test2 seconds
memory limit per test256 megabytes
You are given an array a of 𝑛 positive integers.
You can use the following operation as many times as you like: select any integer 1≤𝑘≤𝑛 and do one of two things:
decrement by one 𝑘 of the first elements of the array.
decrement by one 𝑘 of the last elements of the array.
For example, if 𝑛=5 and 𝑎=[3,2,2,1,4], then you can apply one of the following operations to it (not all possible options are listed below):
decrement from the first two elements of the array. After this operation 𝑎=[2,1,2,1,4];
decrement from the last three elements of the array. After this operation 𝑎=[3,2,1,0,3];
decrement from the first five elements of the array. After this operation 𝑎=[2,1,1,0,3];
Determine if it is possible to make all the elements of the array equal to zero by applying a certain number of operations.
Input
The first line contains one positive integer 𝑡 (1≤𝑡≤30000) — the number of test cases. Then t test cases follow.
Each test case begins with a line containing one integer 𝑛 (1≤𝑛≤30000) — the number of elements in the array.
The second line of each test case contains n integers 𝑎1…𝑎𝑛 (1≤𝑎𝑖≤106).
The sum of n over all test cases does not exceed 30000.
Output
For each test case, output on a separate line:
YES, if it is possible to make all elements of the array equal to zero by applying a certain number of operations.
NO, otherwise.
The letters in the words YES and NO can be outputed in any case.
- 题解:
该题属于div.2D题中较为简单的问题,观察可以发现我们只需要处理当a[i]>=a[i-1]且当a[i]>=a[i+1](同时等于不用处理)时的情况,因为如果没有这种情况那么序列一直是单调的,必定有解,该种情况下我们只需要处理一边,即将序列处理为单调的,具体操作还需要维护一个偏移量,我选择处理序列右边的这种情况,该种情况下对于每个a[i]>a[i-1],序列左端必定全部下降dlt = a[i]-a[i-1]个,才能将序列处理为单调递减的;然后判断之后与当前的每个数值是否合法。
题意:
该题意是给你一个序列,你能拥有两种操作,一种是选择k,令a[1]a[k]全体减1;另一种是选择k令a[k]a[n]全体减1;
询问在经过若干次操作后,是否可以使序列全减为0;
方法2:
大佬们用差分序列做,现求出该序列的差分序列,对于每个d[i]若d[i]<0,那么a[1]必定要向下位移|d[i]|个,最后判断a[1]值是否合法;
总结:
该题属于思维题,处理序列,感觉序列问题总与单调性有一定的联系,以后碰到序列问题应及时往这方面去想,提高构造能力
代码如下:
/*************************************************************************
> File Name: CFD.cpp
# Author: Badwoman
# mail: 1194446133@qq.com
> Created Time: 2020年11月13日 星期五 18时27分00秒
************************************************************************/
#include<set>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<map>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#define ll long long
#define ull unsigned long long
#define pb push_back
#define mp make_pair
using namespace std;
const int N = 3e4+10;
int arr[N],n,mi[N];
void solve(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d",&arr[i]);
}
mi[n] = arr[n];//mi序列能够实时得到该序列下一个最小值
for(int i=n-1;i>=1;--i){
mi[i] = min(arr[i],mi[i+1]);
}
bool flag = true;
int dlt = 0,mina = arr[1];//序列偏移量,利用他能够得到真正序列
for(int i=2;i<=n;++i){
mina = min(mina,arr[i]-dlt);
int now = arr[i]-dlt,minb = mi[i]-dlt;
if(now<0){
flag = 0;break;
}
if(arr[i]>=arr[i-1]&&arr[i]>=arr[i+1]){
if(arr[i]==arr[i-1]&&arr[i]==arr[i+1])continue;
dlt += now - mina;//维护偏移量
//mina-=now - minb;
if(minb<now-mina){
flag = false ;break;
}
mina = now;
}
}
printf("%s\n",flag == true?"YES":"NO");
}
}
int main(){
solve();
return 0;
}