增减序列
增减序列
最终的目的是让整个序列相等
操作只有一种使\([l,r]\)区间全都\(+1\)
既然整个序列相等,那么整个序列的差分序列应为0
操作的话就可以转化为\(a[l]+=1,a[r+1]-=1\)
求的是最少操作次数
通过原数列,我们先求一个原始的差分序列,然后每次操作使,正数-1,负数+1,这样就使差分序列往目标:靠近 0序列
(当然差分序列第1项不用为0,而且首项可以为任何数,思考为什么?)
设正数的和p,负数绝对值和q,那么就很容易的到一个最少操作次数 \(max(p,q)\)
(简单描述下怎么来的,操作\(min(p,q)\)次后,p,q中小的变为0,还剩\(abs(p-q)\)次 ,所以最少操作次数 \(min(p,q)+abs(p-q)=max(p,q)\))
至于最少操作后的结果
操作\(min(p,q)\)次后,那么一定剩下几项不为0
此时可以考虑两中情况
-
与差分序列首项想相加减
这种情况因为改变首项,所以最终序列会改变,故会得到\(abs(p-q)\)种序列 -
与第\(n+1\)项相加减
这种情况并不改变首项,只有一种序列(第n+1项无论怎么变,都不影响最终序列,也可以思考为什么)
总的来说会得到\(abs(p-q)+1\)种方案
- code
#include<iostream>
using namespace std;
const int maxn=1e5+10;
int a[maxn];int n;
int cf[maxn];
long long p=0,q=0;
long abs(long x){
return x<0?-x:x;
}
int main(){
cin>>n;
for(int i=1;i<=n;++i){
cin>>a[i];
cf[i]=a[i]-a[i-1];
}
for(int i=2;i<=n;++i){
if(cf[i]>0) p+=cf[i];
if(cf[i]<0) q-=cf[i];
}
cout<<max(p,q)<<endl<<abs(p-q)+1<<endl;return 0;
}