增减序列为什么要五个字

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

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

输入格式

第一行输入正整数 n

接下来 n 行,每行输入一个整数,第 i+1 行的整数代表 ai

输出格式

第一行输出最少操作次数。

第二行输出最终能得到多少种结果。

数据范围

0<n≤105

0≤ai<2147483648

输入样例:
4
1
1
2
2
输出样例:
1
2

给一段区间增减用差分处理会很快

差分之后,不难发现要把数组处理成 N,0,0,0,0,。。。这样的数列,

要最少操作数,贪心想一下,差分之后的数列有两种情况

1,全是正数/负数

2,有正有负

如果全是正数/负数,那么只能一个一个数处理,即(一个数一个数的+/-1,)在差分数组中,就变成了第一个数+1,后面非0数-1(负数相反 第一个数-1,后面非0数+1)。那么操作数就是第二项(包括第二项)到最后项数字之和的绝对值。

如果有正有负,根据贪心,我们尽量要把正负相互抵消,然后全部变成整数/负数,这个时候 操作数就是 min(第二项之后的正数和 , 第二项之后的负数和的绝对值 ),全部变成正/负数之后,就按照第一条的变换,此时,余下的正/负数和是 (第二项之后的正数和 - 第二项之后的负数和的绝对值 )的绝对值。

操作数

假设x表示差分数列第二项之后的正数和,

y表示差分数列第二项之后的负数和的绝对值

那么操作数就等于 全部变成正/负的操作数+全是正/负的操作数 =

min(x,y) +abs(x-y)

方案数

根据全是正/负数的变换规则 , 我们可任意选择第二项开始的非0的数和首项数操作,则,能有几个操作数就有多少种类

即 总类数 = abs(x-y)

#include<iostream>
#include<algorithm>

using namespace std;
using ll = long long;
const int maxn=1e5+6;

ll a[maxn];
int n;
void init(){
    for(int i=n;i>0;i--){
        a[i] -= a[i-1];
    }
}
void getNS(ll &x,ll &y){
    x=y=0;
    for(int i=2;i<=n;i++){
        if(a[i]>0) x+=a[i];
        if(a[i]<0) y+=a[i];
    }
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    init();
    ll x,y;
    getNS(x,y);
    y*=-1;
    cout<<(min(x,y)+abs(x-y))<<endl;
    cout<<(abs(x-y)+1)<<endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值