[Poetize6] IncDec Sequence

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;
}
posted @ 2018-09-19 14:40  YoungNeal  阅读(166)  评论(0编辑  收藏  举报