差分序列-ACwing

https://www.acwing.com/problem/content/

// a1 a2 a3 a4 ... an
// b[1] = a[1];
// b[2] = a[2] - a[1];
// // a[2] = b[2] + b[1];
// b[3] = a[3] - a[2];
// a[3] = a[2] + b[3] = b[2] + b[1] + b[3];
// .
// .
// b[n] = a[n] - a[n - 1];
// a[n] = b[1] + b[2] + ... + b[n];

// 说明 a 数组是 b 数组的前缀和数组
// 在原数组里面选一个区间 (l , r) 等价于在差分数组里面 b[l] += 1  , b[r + 1] -= 1; 即只对一个数修改

// 要使数列中所有的数都相等 可以得到 a[1] = a[2] =... = a[n] 那么 b[2] = ... b[n] = 0;
// b[1] = a[1] 只要 a[1] != 0 那么 b[1] 也不等于 0

// 对于 b 数组来说 每次选择两个点 尽量的使次数最少 最终求得数列有多少种 取决于 b[1] 是多少 

// 次数最少怎么求呢 ? 我们可以将 2 - n 中的 负数 + 1 正数 - 1 两两抵消 假设正数 sum = p , 负数 sum = q 
// 那么我们可以 p 和 q 中较小的那一个 那么剩下的 P - q 就是我们需要用 b[1] 来抵消的
// 那么 b[1] 是多少呢 ? 首先 p - q 是我们需要操作的b[1]的次数 , 我么可以操作 b[1] 也可以让同符号的数抵消 
// 也可以操作 b[i] 和 b[n]让同类型的抵消  但是操作 b[n] b[1] 不会变 所以只需要看第一种就可以了 
// b[1] 可以得到多少个 取决于我们操作多少次 , 我们可以操作 0次 b[i]和b[n] 也可以操作 1 2 3.. p - q 次 
// 所以最后的结果就是 p - q + 1
// 所以加上 b[1] 一开始的值 我们能够得到的 b[1]的值就是 abs(p - q) + 1 次
// b[l] += 1 , b[n + 1] -= 1 操作 l - n 之间的数就是操作 n + 1 位置上的数 , 不会影响数组 所以可以保证不会让 b[n]最后不是 0
#include
#include
#include

using namespace std;

const int N = 1e5 + 10;

int a[N];
int b[N];

int main()
{
    int n;
    cin >> n;
    
    for(int i = 1 ; i <= n ; i ++) cin >> a[i];
    for(int i = 1 ; i <= n ; i ++) b[i] = a[i] - a[i - 1];
    
    long long p = 0 , q = 0;
    for(int i = 2 ; i <= n ; i ++)
    {
        if(b[i] <= 0) p -= b[i];
        else q += b[i];
    }
    
    cout << max(p , q) << endl;
    cout << abs(p - q) + 1 << endl;
    
    return 0;
}description/102/

你可能感兴趣的:(蓝桥杯,算法)