差分
1、对于给定一个序列 A ,它的差分序列为:
B [ 1 ] = A [ 1 ] , B [ i ] = A [ i ] − A [ i − 1 ] ( 2 < = i < = n ) B[1] = A[1],B[i] = A[i] - A[i-1](2 <= i <= n) B[1]=A[1],B[i]=A[i]−A[i−1](2<=i<=n)
2、差分 和 前缀和 是一对逆运算:差分序列 B 的前缀和就是序列 A,前缀和 S 的差分序列也是序列A。
差分序列 B 的前缀和:
= B [ 1 ] + B [ 2 ] + B [ 3 ] + . . . + B [ i ] = B[1] + B[2] + B[3] + ... + B[i] =B[1]+B[2]+B[3]+...+B[i]
= A [ 1 ] + A [ 2 ] − A [ 1 ] + A [ 3 ] − A [ 2 ] + . . . + A [ i ] − A [ i − 1 ] =A[1] + A[2] - A[1] + A[3] - A[2] + ... + A[i] - A[i - 1] =A[1]+A[2]−A[1]+A[3]−A[2]+...+A[i]−A[i−1]
= A [ i ] = A[i] =A[i]
前缀和 S 的差分序列:
= S [ i ] − S [ i − 1 ] = S[i] - S[i-1] =S[i]−S[i−1]
= A [ 1 ] + A [ 2 ] + . . . + A [ i − 1 ] + A [ i ] − ( A [ 1 ] + A [ 2 ] + . . . + A [ i − 1 ] ) = A[1] + A[2] + ... + A[i-1] + A[i] - (A[1] + A[2] + ... + A[i-1]) =A[1]+A[2]+...+A[i−1]+A[i]−(A[1]+A[2]+...+A[i−1])
= A [ i ] = A[i] =A[i]
3、作用:把序列 A 的区间 [ l , r ] [l,r] [l,r] 加 d(即把 A l , A l + 1 , . . . , A r A_l,A_{l+1},...,A_r Al,Al+1,...,Ar 都加上 d),其差分序列 B 的变化为 B l B_l Bl 加 d, B r + 1 B_{r+1} Br+1 减 d,其他位置不变。
A 序列加d : A [ l ] + d , A [ l + 1 ] + d , . . . , A [ r ] + d A[l]+d,A[l+1] + d,...,A[r]+d A[l]+d,A[l+1]+d,...,A[r]+d
变化后差分序列:
B [ l ] = A [ l ] + d − A [ l − 1 ] = B [ l ] 原 + d B[l] = A[l] + d - A[l-1] = B[l]_{原} + d B[l]=A[l]+d−A[l−1]=B[l]原+d
B [ l + 1 ] = A [ l + 1 ] + d − ( A [ l ] + d ) = B [ l + 1 ] 原 B[l+1] = A[l+1] + d - (A[l] + d) = B[l+1]_{原} B[l+1]=A[l+1]+d−(A[l]+d)=B[l+1]原
…
B [ r + 1 ] = A [ r + 1 ] − ( A [ r ] + d ) = B [ r + 1 ] 原 − d B[r+1] = A[r+1] - (A[r] + d) = B[r+1]_{原} - d B[r+1]=A[r+1]−(A[r]+d)=B[r+1]原−d
AcWing 100. IncDec序列
题目:
给定一个长度为 n 的数列 a1,a2,…,an,每次可以选择一个区间 [l,r],使下标在这个区间内的数都加一或者都减一。
求至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列可能有多少种。
输入格式
第一行输入正整数 n。
接下来 n 行,每行输入一个整数,第 i+1 行的整数代表 ai。
输出格式
第一行输出最少操作次数。
第二行输出最终能得到多少种结果。
数据范围
0 < n ≤ 10^5
0 ≤ ai < 2147483648
输入样例:
4
1
1
2
2
输出样例:
1
2
思路:
题目对序列 A 的操作就是对 B 1 , B 2 , . . . , B n B_1,B_2,...,B_n B1,B2,...,Bn 任选2个数,一个加1,一个减1.
题目要求序列 A 的每一个数都要相同,可以转换为 差分序列 B 2 , B 3 , . . . , B n B_2,B_3,...,B_n B2,B3,...,Bn 全变为 0.
对 B 1 , B 2 , . . . , B n B_1,B_2,...,B_n B1,B2,...,Bn 任选2个数 有四种情况:
1、选 B i 和 B j , 2 < = i , j < = n B_i 和 B_j, 2 <= i,j <= n Bi和Bj,2<=i,j<=n , 为尽量让序列为 0 ,应选择一正一负,相互抵消,逐渐趋近0.
2、选 B 1 , B j 其 中 2 < = j < = n B_1,B_j 其中 2 <= j <= n B1,Bj其中2<=j<=n
3、选 B i , B n + 1 其 中 2 < = i < = n B_i,B_{n+1} 其中 2 <= i <= n Bi,Bn+1其中2<=i<=n
4、选 B 1 , B n + 1 B_1,B_{n+1} B1,Bn+1 相当于选取全部加减,没有意义。
设 差分序列 B 中正整数的和为 P,负整数的和为 Q,在正负数的选取下,先采用第一种选法,可选min(P, Q),还有|P-Q|种没有匹配,可以选择第二种或者第三种,总次数为 min(P, Q) + |P-Q| = max(P, Q);
根据|P - Q| 次第二或第三种选择,可以选择出 |P - Q| + 1 种 B 1 B_1 B1 ,所以 A 序列 有|P - Q| + 1 种。
算法:
import java.util.*;
public class Main{
public static int MAX = 100010;
public static int[] A = new int[MAX];
public static int[] B = new int[MAX];
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
long poSum = 0, neSum = 0;
for(int i = 0; i < n; i++) {
A[i] = scanner.nextInt();
if(i == 0) B[i] = A[i];
else {
B[i] = A[i] - A[i-1];
if(B[i] > 0) poSum += B[i];
else neSum -= B[i];
}
}
System.out.println(Math.max(poSum, neSum));
System.out.println(Math.abs(poSum - neSum) + 1);
}
}