欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[Poetize6] IncDec Sequence

程序员文章站 2022-07-12 17:40:43
...

Description

有一个长度为\(n(n\leq 100000)\)的数列,每次可以给一个区间\([l,r]\)加1或者减1.问要多少次操作让整个数列一样,并求出最少操作的前提下,最终得到的数列有多少种。

Solution

有生之年自己想出来一道紫牌题还是很高兴的。
看到这题立马想到了差分。因为区间加可以转化为端点加减,最后让它们相等就是除了第一个元素剩下的都为0嘛!
那怎么找这个最小次数呢?我们发现,题目给的条件非常好,既可以加又可以减。那么对于差分数列的任意两个数,只要它们符号不同,那就可以对这两个元素进行操作。我们记录\(sum1\)表示差分数组负数的个数,\(sum2\)记录正数的个数。所以第一问的答案很显然就是\(max(sum1,sum2)\)。那第二问呢?观察到除了1以外的元素都变成0之后,第一个元素有多少种不同的方案,整个序列就有多少种不同的方案。假设\(sum1>sum2\)。我们先把所有的正数变为0,此时还需要操作\(sum1-sum2\)次。而每一次都可以选择是否对第一个元素进行操作,所以第一个元素总共有\(sum1-sum2+1\)个可能。

Code

#include<cctype>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using std::min;
using std::max;
using std::swap;
#define int long long
const int N=100005;

int n,sum1,sum2;
int val[N],cf[N];

inline int abs(int a){
    if(a<0) return -a;
    return a;
}

int getint(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch))w|=ch=='-',ch=getchar();
    while( isdigit(ch))X=X*10+ch-48,ch=getchar();
    return w?-X:X;
}

signed main(){
    n=getint();
    for(int i=1;i<=n;i++)
        val[i]=getint(),cf[i]=val[i]-val[i-1];
    for(int i=2;i<=n;i++){
        if(cf[i]<0) sum1+=cf[i];
        else sum2+=cf[i];
    }
    printf("%lld\n",max(abs(sum1),sum2));
    printf("%lld\n",abs(sum1+sum2)+1);
    return 0;
}