题解 P4552 【[Poetize6] IncDec Sequence】

Solution IncDec Sequence

题目大意:给定一个序列,你可以将一段子序列集体\(+1\)\(-1\),求最小的操作次数使得所有数相等,以及操作方案数

分析:

区间加减不好考虑,我们可以考虑差分

令原数组\(val[0] = 0\),差分数组\(d[i] = val[i] - val[i - 1]\)

然后问题就变成了,给你一个序列,每次可以将\(1\)个数\(+1\)同时将另一个数\(-1\),求最小操作次数使得所有数下标不为\(1\)的数为\(0\)

我们发现,这种方式可以同时改变\(2\)个数,应当优先采用

\(q = \sum d[i] \quad | \quad d[i] > 0 \; and \; i\neq 1\),\(p = \sum d[i] \quad | \quad d[i] < 0 \; and \; i\neq 1\)

这种方法最多采用\(min(p,q)\)

然后考虑剩下的,这个需要\(|p-q|\)

所以需要\(min(p,q) + |p -q| = max(p,q)\)

方案:

方案取决于剩下的数,显然剩下的都和\(d[1]\)同号了,有些可以作用于\(d[1]\),有些可以作用于\(d[n + 1]\),所以有\(|p - q| + 1\)种不同的\(d[1]\)取值,所以方案有\(|p - q| + 1\)

#include <algorithm>
#include <cstdio>
#include <cctype>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 100;
ll val[maxn],d[maxn],sum,vsum;
int n;
int main(){
    scanf("%d",&n);
    for(int i = 1;i <= n;i++)scanf("%lld",val + i);
    for(int i = 2;i <= n;i++){
        d[i] = val[i] - val[i - 1];
        if(d[i] > 0)sum += d[i];
        else vsum -= d[i];
    }
    printf("%lld\n",max(sum,vsum));
    printf("%lld\n",abs(sum - vsum) + 1);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/colazcy/p/11628345.html