AcWing-100.增减序列
¶首先来首歌曲来放松一下吧!
题目链接:100. 增减序列
¶题目背景:
前缀和和差分序列是互逆的!
题目分析处详细解释!
¶题目描述
给定一个长度为 n 的数列 a1,a2,…,an,每次可以选择一个区间 [l,r],使下标在这个区间内的数都加一或者都减一。
求至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列可能有多少种。
¶输入格式
第一行输入正整数n。
接下来n行,每行输入一个整数,第i+1行的整数代表ai。
¶输出格式
第一行输出最少操作次数。
第二行输出最终能得到多少种结果。
¶数据范围
0<n≤105
0≤ai<2147483648
¶输入样例:
1 |
|
¶输出样例:
1 |
|
¶题目分析:
¶题目要求:
在一个序列内任意选择区间,将区间内的数都进行加一或减一操作,使得最后的序列数字都一样,问对少步数和达到最少步数的方法总数!
¶解题思路:
先引入差分:
a数组是普通序列,b数组是a数组的差分序列!
差分序列定义:b[i] = a[i] - a[i-1], b[1] = a[1]
然后就是两个定理:
- b 序列是 a 序列的差分序列(定义就是这样定义的!)
- a 序列是 b 序列的前缀和序列(开始证明!)
a[i] 可以写为 b[1] + b[i]:如下:
1 |
|
证明成立!
接下来开始看题!
在一个(L,R)序列上加一个常数 C,相当于:
1 |
|
这个可以稍微想一下:或者那笔画一下!
假设序列从下标为1开始存储!
再想一下:要想全部数变成同样的数,可以让b数组变成什么样?
当然是让 b[1] ~ b[n] 都为0,也就是整个序列此时都是 a[1] ,即 n 个 a[1]!
首先先将差分序列处理出来,我们可以想,既然是区间的端点出进行加一或减一,那么,让一个正数去–,一个负数去++是不是可以更快的达到为0的目的!
所以可以将差分序列的正数和负数都累加一下计算出来!得到两个值!
这样的话:选取一个区间就会使累积的正数(假如是40)和一个负数(假如是34)减一,这样直到其中一方为0,这样正负数匹配就结束了,可能剩下的多出来的一方(不为0的)就需要和b[0]或b[n + 1]来处理。
正负匹配需要最少为 34次,即min(34, 40)
多出来的最少需要 40 - 34 次,即abs(34 - 40)
或者直接这样想,一次就需要正负减1,全部处理完,自然就是最大的数了!就是40次,直接max(34, 40)
所以最少次数为:min(34, 40) + abs(34 - 40) = max(34, 40)
以及最后的方案数:
min(34, 40)
是死的,最后不一样的就是多出来的(不为0的)的数的方案,即
abs(40- 34) + 1
!
¶题解:
讲解是下标从1开始,我是从0开始,都一样的!
防止溢出,使用 long long!
1 |
|