这道题可以转化为求出原数列的差分数组,然后使得最终得到的数列中所有数都相等就可以转化为将差分数组中的所有数都变成零,并求出最小的操作次数以及最终有多少种方式
我们再来看一看题中所说的操作,选定一个区间([l,r])并将其中的数+1或-1,设差分数组(b[i]),那么可以发现这个操作的本质就是将(b[l])加一或减一以及将(b[r+1])减一或加一,为了使最终操作次数最少,尽量要选出差分数组里的一个正数和一个负数来执行这个操作
举个例子,差分数组0 3 -2 3 0 -5 -3
我们执行上述操作后可以得到另外几个差分数组0 0 0 0 0 -1 -3或者0 0 -2 0 0 -2 0,根据题目的要求可以很显然的发现通过这两种方式求的的最终答案是一样的,设差分数组中正数的和为(s1),负数的和的绝对值为(s2),那么执行这一种操作的次数即为(min(s1,s2))
然后还有两种很重要的操作,第一种是选择([0,i])区间进行加减操作,第二种是选择([i,n])区间,可以将差分数组中的一个数变为零,执行这一种操作的的次数即为(|s1-s2|),并且所得结果的种数也取决于这两种操作,最高可以达到(max(s1,s2)),最低可以达到(min(s1,s2)),所以答案种数便为(|s1-s2|+1)
综上所述,(ans1=min(s1,s2)+|s1-s2|=max(s1,s2)),(ans2=|s1-s2|+1)
代码比较简单
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,a[100003],b[100003],s1,s2;
signed main()
{
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
if(i!=1)
{
b[i]=a[i]-a[i-1];
if(b[i]>0)
s1+=b[i];
else
s2-=b[i];
}
}
cout<<max(s1,s2)<<endl<<abs(s1-s2)+1;
return 0;
}