Description
有一个长度为\(n(n\leq 100000)\)的数列,每次可以给一个区间\([l,r]\)加1或者减1.问要多少次操作让整个数列一样,并求出最少操作的前提下,最终得到的数列有多少种。
Solution
有生之年自己想出来一道紫牌题还是很高兴的。
看到这题立马想到了差分。因为区间加可以转化为端点加减,最后让它们相等就是除了第一个元素剩下的都为0嘛!
那怎么找这个最小次数呢?我们发现,题目给的条件非常好,既可以加又可以减。那么对于差分数列的任意两个数,只要它们符号不同,那就可以对这两个元素进行操作。我们记录\(sum1\)表示差分数组负数的个数,\(sum2\)记录正数的个数。所以第一问的答案很显然就是\(max(sum1,sum2)\)。那第二问呢?观察到除了1以外的元素都变成0之后,第一个元素有多少种不同的方案,整个序列就有多少种不同的方案。假设\(sum1>sum2\)。我们先把所有的正数变为0,此时还需要操作\(sum1-sum2\)次。而每一次都可以选择是否对第一个元素进行操作,所以第一个元素总共有\(sum1-sum2+1\)个可能。
Code
#include<cctype>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using std::min;
using std::max;
using std::swap;
#define int long long
const int N=100005;
int n,sum1,sum2;
int val[N],cf[N];
inline int abs(int a){
if(a<0) return -a;
return a;
}
int getint(){
int X=0,w=0;char ch=0;
while(!isdigit(ch))w|=ch=='-',ch=getchar();
while( isdigit(ch))X=X*10+ch-48,ch=getchar();
return w?-X:X;
}
signed main(){
n=getint();
for(int i=1;i<=n;i++)
val[i]=getint(),cf[i]=val[i]-val[i-1];
for(int i=2;i<=n;i++){
if(cf[i]<0) sum1+=cf[i];
else sum2+=cf[i];
}
printf("%lld\n",max(abs(sum1),sum2));
printf("%lld\n",abs(sum1+sum2)+1);
return 0;
}