增减序列

戳我进原题
题意: 给定一个长度为 n n n的序列 a a a,每次可以指定一个区间给这个区间的所有数统一加 1 1 1或减 1 1 1,问最少要操作多少次可以使得序列 a a a中的所有数都相同,并且输出最终可能得到的序列个数。
数据范围: 1 ≤ n ≤ 1 0 5 1\leq n\leq 10^5 1n105

题解:
区间的简单操作可以想到差分:
那么定义 a a a的差分序列为 b b b
如果要使得所有数都相同,则使得 b [ 2 ] , b [ 3 ] , . . .   , b [ n ] b[2],b[3],...\ ,b[n] b[2],b[3],... ,b[n]都等于 0 0 0
对于序列 a a a的区间 [ l , r ] [l,r] [l,r]操作即对差分序列 b b b b [ l ] b[l] b[l] b [ r + 1 ] b[r+1] b[r+1]操作
[ l , r ] [l,r] [l,r]区间加 1 1 1时,相当于 b [ l ] = b [ l ] + 1 b[l]=b[l]+1 b[l]=b[l]+1 b [ r + 1 ] = b [ r + 1 ] − 1 b[r+1]=b[r+1]-1 b[r+1]=b[r+1]1
[ l , r ] [l,r] [l,r]区间减 1 1 1时,相当于 b [ l ] = b [ l ] − 1 b[l]=b[l]-1 b[l]=b[l]1 b [ r + 1 ] = b [ r + 1 ] + 1 b[r+1]=b[r+1]+1 b[r+1]=b[r+1]+1
因为我们需要将所有的 b [ 2 , . . .   , n ] b[2,...\ ,n] b[2,... ,n]都操作为 0 0 0,又因为每次需要使得一个 b [ l ] b[l] b[l] 1 1 1或减 1 1 1,另一个 b [ r + 1 ] b[r+1] b[r+1] 1 1 1或加 1 1 1,即 b [ l ] b[l] b[l] b [ r + 1 ] b[r+1] b[r+1]进行相反的操作,所以我们尽可能选择一个需要由负变 0 0 0 b [ i ] b[i] b[i]和一个需要由正变 0 0 0 b [ j ] b[j] b[j],这样一次操作可以操作两个 b b b

当由负变 0 0 0 b [ i ] b[i] b[i]和由正变 0 0 0 b [ j ] b[j] b[j]其中有一个已经没有时,我们之后的操作可以有两个选择,要么选择 b [ 1 ] b[1] b[1],要么选择 b [ n + 1 ] b[n+1] b[n+1],这两者对于最终操作的数量是没有影响的,但是这两者影响的是最少操作数量下会得到不同的序列,即我们可以选择对 b [ 1 ] b[1] b[1]操作 [ 0 , a b s ( p o s , n e g ) ] [0,abs(pos,neg)] [0,abs(pos,neg)]次,故总共是 a b s ( p o s , n e g ) + 1 abs(pos,neg)+1 abs(pos,neg)+1种不同序列。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

typedef long long ll;
const int N = 1e5 + 10;
ll a[N];
int n;

int main()
{
    
    
    ll pos = 0, neg = 0;
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
    for(int i = n; i >= 1; --i) a[i] -= a[i - 1];
    for(int i = 2; i <= n; ++i) 
        if(a[i] > 0) pos += a[i];
        else neg -= a[i];
    
    
    printf("%lld\n%lld\n", max(pos, neg), abs(pos - neg) + 1);
}

猜你喜欢

转载自blog.csdn.net/weixin_43900869/article/details/112781563