洛谷题单指南-前缀和差分与离散化-P4552 [Poetize6] IncDec Sequence

原题链接:https://www.luogu.com.cn/problem/P4552

题意解读:对一组数字序列,进行若干次区间+1或者-1操作,最终使得所有数字一样,计算最少的操作次数,以及能得到多少种不同序列。

解题思路:

要使得序列每一个数字都相同,则其差分除了第一项之外其余项都是0。

因此,问题转化为:给定一个差分数组a[],每次对两个数a[l],a[r+1]分别进行+1、-1操作(对于前缀和数组就是对[l,r]每个数都+1或-1),最终使得除a[1]之外都变成0,而a[1]的数值决定其前缀和数组有多少种不同的序列。

一共有如下几种可能的操作:

a[]中除a[1]外存在一正一负时:

  操作一:对正数-1,对负数+1,这样可以尽快将所有数变为0,保证操作次数最少

a[]中除a[1]外只有正数或者负数时:

  操作二:可以对a[1]+1或-1,对正数-1或对负数+1,该操作影响最终序列的种类

  操作三:可以对正数-1或对负数+1,对a[n+1]+1或-1

所以,对于一个差分数组a[],设除了a[1]所有正数之和为up,所有负数之和的绝对值为down

那么优先进行操作一,直到只剩下正数或者负数,操作次数为min(up, down)

接下来,只剩下正数或者负数,可以进行操作二或者操作三,任选其一即可,操作次数为abs(up - down)

总操作次数为:min(up, down) + abs(up - down)

可能得到的序列取决于进行操作二的次数,可以有0 ~ abs(up - down)次操作二,一共对应1 + abs(up - down)种序列。

100分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 100005;
int s[N], a[N];
int n;
long long up, down;

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++)
    {
        cin >> s[i];
        a[i] = s[i] - s[i - 1];
    }

    for(int i = 2; i <= n; i++)
    {
        if(a[i] > 0) up += a[i];
        else if(a[i] < 0) down += abs(a[i]);
    }

    cout << min(up, down) + abs(up - down) << endl;
    cout << 1 + abs(up - down);

    return 0;
}

 

posted @ 2024-08-01 14:50  五月江城  阅读(14)  评论(0编辑  收藏  举报