AcWing 100 增减序列

题目

给定一个长度为 n 的数列 a1,a2,,an ,每次可以选择一个区间 [l,r] ,使下标在这个区间内的项都加一或者都减一

求至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列可能有多少种

分析

对于区间加减的问题,可以考虑用差分数列解决

bi=aiai1 ,那么选择一个区间 [l,r]1 就等价于 bl+1,br+11 ,区间减 1 就等价于 bl1,br+1+1

所以问题转化为了 从 b1,b2,,bn+1 中任意选出两项,一项加 1 ,另一项减 1,若干步后使 b2=b3==bn=0

任选两个项的方法有四种:

  • bi,bj,2i,jn
  • b1,bj,2jn
  • bi,bn+1,2in
  • b1,bn+1

而第四类方法只会浪费步骤,所以不考虑

第一种方法在一正一负的情况下可以一次改变两个数的值,应该尽可能采取这种方法

当无法采用第一种方法时,可以采用第二种或第三种

pb1,b2,,bn 中的正数项总和, q 为负数项总和的绝对值,即:

p=i=2nmax(bi,0),q=|i=2nmin(bi,0)|

正负数配对可执行 min(p,q) 次方法1,而剩下的数则执行方法2或方法3,一共 min(p,q)+|pq|=max(p,q)

根据方法2和方法3的选取情况,能产生 |pq|+1a1

代码

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

int n;
ll a[100000 + 5];

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
        scanf("%lld", &a[i]);
    ll p = 0, q = 0;
    for(int i = 2; i <= n; i++) {
        p += max(a[i] - a[i - 1], 0ll);
        q += abs(min(a[i] - a[i - 1], 0ll));      
    }
    printf("%lld\n%lld\n", max(p, q), abs(p - q) + 1);
    return 0;
}
posted @   f(k(t))  阅读(48)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示