Acwing 100 IncDec序列 (差分数组+贪心)
题面
给定一个长度为 n 的数列 a1,a2,…,an,每次可以选择一个区间 [l,r],使下标在这个区间内的数都加一或者都减一。
求至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列可能有多少种。
输入格式
第一行输入正整数n。
接下来n行,每行输入一个整数,第i+1行的整数代表ai。
输出格式
第一行输出最少操作次数。
第二行输出最终能得到多少种结果。
输入样例:
4
1
1
2
2
输出样例:
1
2
思路
差分数组是前缀和的一个逆过程,既从2开始的每个数都对于原数组的数对前一个数求差值。如果我们对一个差分数组求前缀和,那么我们就得到了原数组,所以这两个是互逆的过程。这道题目,给你一个数组,求多少次的区间修改后可以使得数组各个值相等(每次操作只能加减1),那么我们对原数组求一个差分,然后根据题意我们需要使得差分数组从2到n的元素都等于0。那么我们再来看差分数组区间修改的操作,我们对差分数组的第l个元素+=1,第r+1个元素-=1,然后求前缀和就完成了区间的修改了。那么现在我们需要对原数组的差分数组,进行若干次的两个元素的加减操作,那么我们需要得到正数和负数各自的和。需要我们执行的操作次数就等于正数和负数的绝对值的最小值加上一个大的减去小的(有些没办法匹配,我们需要利用首元素进行修改,这样对差分数组没有影响),而修改的数组种类就等于p-q的绝对值+1(想一想,为什么?)。
代码实现
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
ll a[maxn],n,p,q;
int main () {
cin>>n;
for (int i=1;i<=n;i++) cin>>a[i];
for (int i=2;i<=n;i++) {
ll c=a[i]-a[i-1];
if (c>0) p+=c;
else q-=c;
}
ll ans1=max(p,q);
ll ans2=abs (p-q)+1;
cout<<ans1<<endl<<ans2<<endl;
return 0;
}