P4552题解

题解P4552

luogu

题目描述

给定一个长度为\(n\)的数列,每次可以选择区间 \([l,r]\), 使得这个区间内的数都加一或者减一。

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

输入输出

第一行一个正整数\(n\)接下来 \(n\) 行,每行一个整数,第\(i + 1\) 行的整数表示\(a_i\)

第一行输出最少操作次数
第二行输出最终能得到多少种结果

样例数据

\(in\)

6
4 8 6 5 10 7

\(out\)

9
4

题解

因为是区间加减,我们就考虑到使用差分数组。即新定义一个数组\(c\),使得\(c[i] = a[i+1] - a[i]\)

这样,看到样例,我们就有

\[ c = \{ 4 , -2 , -1 , 5 , -3 \} \]

对于区间\([l,r]\),加1减1的操作对c数组的影响为

\[ [l,r]都加一:a[l-1]++,a[r]-- \\ [l,r]都减一:a[l-1]--,a[r]++ \]

\(x,y\),使得\(x\)\(c\)中所有整数之和,\(y\)\(c\)中所有负数之和再取反。观察前面的结论,我们可以把操作分成两部分:先是正负抵消,剩下的最后一个数,再单独把这个数递减(或加)到零,所以操作次数就是\(max(x,y)\)

举例

c = { 4 , -2 , -1 , 5 , -3 }
c = { 2 ,  0 , -1 , 5 , -3 }
c = { 1 ,  0 ,  0 , 5 , -3 }
c = { 0 ,  0 ,  0 , 5 , -2 }
c = { 0 ,  0 ,  0 , 0 ,  3 }

第二问。回顾操作两个步骤:“先是正负抵消,剩下的最后一个数,再单独把这个数递减(或加)到零。”那么我们第一步进行完以后一定会得到这个数组:

\[ c = \{0,0,0,0,0,···,0,0,x-y \} \]

\(x-y > 0\)时,我们可以选择将区间\([1,n]\)都加\(x-y\),或者将区间\([n,n]\)\(x-y\),这两种操作得到的答案就是最终的答案区间,这个区间覆盖的数字个数就是\(|x-y| + 1\)。所以最终答案为\(|x-y| + 1\)

同理反之亦然。

为什么不用模拟操作?

因为我们已经直接算出结果来了鸭

AC代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
long long max(long long a,long long b){return a > b ? a : b;}
long long n;
long long a[100099];
long long c[100099];
int main(){
    cin >> n;
    for(long long i = 1;i <= n; i++) cin >> a[i];
    long long x,y;
    x = y = 0;
    for(long long i = 1;i < n; i++){
        c[i] = a[i+1] - a[i];
        if(c[i] < 0){
            x -= c[i];
        }else{
            y += c[i];
        }
    }

    cout << max(x,y) << endl;

    cout << abs(x-y) + 1 << endl;

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Cao-Yucong/p/12236078.html