[Poetize6] IncDec Sequence

Description

有一个长度为(n(nleq 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
",max(abs(sum1),sum2));
    printf("%lld
",abs(sum1+sum2)+1);
    return 0;
}
原文地址:https://www.cnblogs.com/YoungNeal/p/9674481.html