差分数组练习2

来源:互联网 发布:淘宝客推广网站大全 编辑:程序博客网 时间:2024/05/02 04:25

加减序列

【题目描述】:

给定一个长度为n的数列{a1,a2...an},每次可以选择一个区间[l,r],使这个区间内的数都加一或者都减一。

问至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列有多少种。

【输入描述】:

第一行一个正整数n

接下来n行,每行一个整数,第i+1行的整数表示ai。

【输出描述】:

第一行输出最少操作次数

第二行输出最终能得到多少种结果

【样例输入】

41122

【样例输出】

12

【数据范围及描述】:

时间:1s 空间:64M

n=100000,0<=ai<2147483648



这题跟练习1一样,都是要用差分数组来实现的。首先读题,同样是要求区间加一或减一,不同的是它让你将这个数列中的数相同。这题一共有两小问。先来看第一小问,第一小问要求我们输出最少的操作次数。以1 1 2 0为例,我们来把差分数组列出来,可以得到1 0 1 -2.因为题目只是要求将所有数变为相同的,所以第一个数可以不用管它。然后我们会发现除去第一个数的其他差分数组中的正数和负数可以相互抵消,但每抵消1个单位就等于一次操作,因此最少的操作次数为max(S1,S2)(S1为差分数组中所有正数之和,S2为差分数组中所有负数绝对值之和)。再来看第二小问很显然为了达到最小步数我们必须先把正数和负数能抵消的全部抵消,而这些步骤最多只有一种情况,因此可以不考虑。但是抵消到只剩下正数或只剩下负数时,就会出现不同的情况。比如0 0 -1 0这个差分数组,其中的-1可以与第一个数抵消(相当于把前两个数加一),或者与最后一个数的后面抵消(相当于把第三和第四个数都加一),再看0 0 2 0,其中的2可以全部与第一个数抵消,也可全部与最后一个数的后面抵消,也可以其中一个与第一个数抵消,另一个数与最后一个数后面抵消。因此我们可以得到这样一个规律,第二个答案就是abs(S1-S2)+1。

AC代码:

#include<iostream>#include<cstdio>#define ll long longusing namespace std;int a[100005],c[100005],n;ll s1,s2;ll ab(ll x){return x>0?x:-x;}ll mx(ll x,ll y){return x>y?x:y;}int main(){scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&a[i]);}for(int i=1;i<=n;i++){c[i]=a[i]-a[i-1];}for(int i=2;i<=n;i++){if(c[i]>0)s1+=c[i];else s2-=c[i];}cout<<mx(s1,s2)<<endl<<ab(s1-s2)+1;return 0;}
AC截图:


这题跟练习1一样,都是要用差分数组来实现的。首先读题,同样是要求区间加一或减一,不同的是它让你将这个数列中的数相同。这题一共有两小问。先来看第一小问,第一小问要求我们输出最少的操作次数。