题目链接
https://codeforces.com/problemset/problem/1700/C
题目描述
给出一个长度为 n n n 的序列 a a a,每次可以进行三种操作中的一种:
- 选择 i i i,将 a 1 , a 2 , ⋯ , a i a_1,a_2,\cdots,a_i a1,a2,⋯,ai 减 1 1 1。
- 选择 i i i,将 a i , a i + 1 , ⋯ , a n a_i,a_{i+1},\cdots,a_n ai,ai+1,⋯,an 减 1 1 1。
- 将所有 a i a_i ai 加 1 1 1。
求最少需要多少次操作将所有 a i a_i ai 变为 0 0 0。
1 ≤ T ≤ 2 × 1 0 4 1\leq T\leq 2\times 10^4 1≤T≤2×104, 1 ≤ n ≤ 2 × 1 0 5 1\leq n\leq 2\times 10^5 1≤n≤2×105, − 1 0 9 ≤ a i ≤ 1 0 9 -10^9\leq a_i\leq 10^9 −109≤ai≤109, ∑ n ≤ 2 × 1 0 5 \sum n\leq 2\times 10^5 ∑n≤2×105。
输入输出样例
输入样例
4
3
-2 -2 -2
3
10 4 7
4
4 -4 4 -4
5
1 -2 3 -4 5
输出样例
2
13
36
33
解题思路
根据题目中的限制条件可知,作减法运算时对两端的区间起效果,加法运算是对所有数起效果的,我们可以使用操作1或操作2把序列变为单调序列,变为单调序列后再累加就方便多了。
算法步骤:
- 使用减法构造一个单调递增的数列;
- 将单调递增序列变为正数序列,以 a 1 a_1 a1的值为准;如果 a 1 a_1 a1的值为正,序列不需要累加
- 将正数序列变为0序列,操作次数以 a n a_n an为准。
操作次数 = 减的次数+将序列变为正数序列次数+将正数序列变为0的次数
以数据4 -4 4 -4
为例:
做题过程中,根据样例给出的数据模拟一下,很快就可以发现规律了。
参考代码
#include <iostream>
#include <cstdio>
using namespace std;
const int MAXN=200005;
int a[MAXN];
int main(){
int t;
//freopen("1700c.txt","r",stdin);
scanf("%d",&t);
while ( t-- ) {
int n;
scanf("%d",&n);
for(int i = 1; i <= n; i++){
scanf("%d", &a[i]);
}
long long sum = 0; //累积减掉的数值
for(int i = n; i >= 2;i--)
if( a[i-1] > a[i]) sum += a[i-1] - a[i];
//printf("%d\n",sum);
if( a[1]-sum>=0 ) printf("%lld\n", sum + a[n]);
else printf("%lld\n",sum+(-1)*(a[1]-sum)*2 + a[n]);
}
return 0;
}