给定一个长度为 n 的数列 a1,a2,…,an,每次可以选择一个区间 [l,r],使下标在这个区间内的数都加一或者都减一。
求至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列可能有多少种。
输入格式
第一行输入正整数 n。
接下来 n 行,每行输入一个整数,第 i+1 行的整数代表 ai。
输出格式
第一行输出最少操作次数。
第二行输出最终能得到多少种结果。
数据范围
0<n≤105
0≤ai<2147483648
输入样例:
4
1
1
2
2
输出样例:
1
2
给一段区间增减用差分处理会很快
差分之后,不难发现要把数组处理成 N,0,0,0,0,。。。这样的数列,
要最少操作数,贪心想一下,差分之后的数列有两种情况
1,全是正数/负数
2,有正有负
如果全是正数/负数,那么只能一个一个数处理,即(一个数一个数的+/-1,)在差分数组中,就变成了第一个数+1,后面非0数-1(负数相反 第一个数-1,后面非0数+1)。那么操作数就是第二项(包括第二项)到最后项数字之和的绝对值。
如果有正有负,根据贪心,我们尽量要把正负相互抵消,然后全部变成整数/负数,这个时候 操作数就是 min(第二项之后的正数和 , 第二项之后的负数和的绝对值 ),全部变成正/负数之后,就按照第一条的变换,此时,余下的正/负数和是 (第二项之后的正数和 - 第二项之后的负数和的绝对值 )的绝对值。
操作数
假设x表示差分数列第二项之后的正数和,
y表示差分数列第二项之后的负数和的绝对值
那么操作数就等于 全部变成正/负的操作数+全是正/负的操作数 =
min(x,y) +abs(x-y)
方案数
根据全是正/负数的变换规则 , 我们可任意选择第二项开始的非0的数和首项数操作,则,能有几个操作数就有多少种类
即 总类数 = abs(x-y)
#include<iostream>
#include<algorithm>
using namespace std;
using ll = long long;
const int maxn=1e5+6;
ll a[maxn];
int n;
void init(){
for(int i=n;i>0;i--){
a[i] -= a[i-1];
}
}
void getNS(ll &x,ll &y){
x=y=0;
for(int i=2;i<=n;i++){
if(a[i]>0) x+=a[i];
if(a[i]<0) y+=a[i];
}
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
init();
ll x,y;
getNS(x,y);
y*=-1;
cout<<(min(x,y)+abs(x-y))<<endl;
cout<<(abs(x-y)+1)<<endl;
}