本文已参与「新人创作礼」活动,一起开启掘金创作之路。
题目:
给定一个长度为n的数列{a1,a2...an},每次可以选择一个区间[l,r],使这个区间内的数都加一或者都减一。 问至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列有多少种。
Input 第一行一个正整数n 接下来n行,每行一个整数,第i+1行的整数表示ai。
Output 第一行输出最少操作次数 第二行输出最终能得到多少种结果
Sample Input 4
1
1
2
2
Sample Output 1
2 分析:题目中的操作是对一整段连续区间进行加一或者减一,因此我们可以想到用差分来解决这道题目,对于原数组a[1],a[2],a[3]……a[n],我们可以求出来差分数组d[1],d[2],d[3]……d[n],由差分数组的性质不难得出我们要想使得整个序列均相同,只需要使得d[2],d[3]……d[n]变为0即可,我们每次修改一段区间都会对差分数组中的两个数进行一次修改,假如我们要使得原数组中i到j中的值均加1,我们就可以使得d[i]+1,d[j+1]-1,若要使得原数组中i~j中的值均减1,我们就可以使得d[i]-1,d[j+1]+1,在未进行修改的差分数组中d[i]的值可能有正有负,我们最终的目的是使得d[2],d[3]……d[n]变为0,所以我们每次修改优先选择d[2],d[3]……d[n]的数进行修改,使其中一个正数-1,同时一个负数+1,就这样最后处理到d[2],d[3]……d[n]中只剩下正数或者负数时我们可以选择d[1]和d[n+1]来进行修改,需要注意的一点是我们对d[n+1]进行修改是不会影响整个数组的最终结果的,但是对d[1]修改是会影响整个数组的最终结果的,所以我们最后选择对d[1]修改还是对d[n+1]修改决定了方案数,假如正数和的绝对值比负数和的绝对值大5,那么我们可以选择与d[1]的操作次数为0,1,2,3,4,5其中之一,不同的操作次数将会使得数组最后的值不同,所以在操作次数一定的情况下,方案数为(正数的和的绝对值和负数的和的绝对值的差,再取绝对值,最后加1),操作数比较好求,我们优先选择正数和负数相抵消,最后在选择绝对值得大的数与d[1]或者d[n+1]进行抵消,所以最少操作数就是正数的和的绝对值和负数的和的绝对值中较大的那个数,下面是代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<map>
#include<cmath>
using namespace std;
int a[100005];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=n;i>=2;i--)
a[i]-=a[i-1];
long long pos =0,neg=0;
for(int i=2;i<=n;i++)
{
if(a[i]>0) pos+=a[i];
else neg-=a[i];
}
cout<<max(pos,neg)<<endl;
cout<<abs(pos-neg)+1<<endl;
return 0;
}