IncDec序列(差分+贪心)

原题链接

  1. 题目大意
    给定一个序列,可以在其连续子序列上进行加一或者减一操作,求使整个序列变成相同数的最小操作数和种数。

  2. 思路
    首要要明确是对[l,r]序列进行加一或者减一操作,可以联想到前缀和,我们对一个数组b的第l项进行减一操作,第r+1项进行加一操作,这样作用到b数组的前缀和序列就是连续的区间段[l,r]内全部进行减一操作。
    这样可以把o(m*n)的时间复杂度转化为o(n)。
    这时候就要利用到差分,之前我也不是很懂,虽然它很简单昨天睡觉前又看了一遍才彻底搞明白。
    差分:
    对于序列A为:a1,a2,a3,……,an;
    A的差分序列B:b1,b2,b3,……,bn;
    b1=a1,b2=a2-a1,bi=ai-a(i-1);
    而等价于ai=b1+b2+……+bi=a1+a2-a1+……+ai-ai-1=ai;
    所以可以得到序列B是A的差分序列,而序列A为B的前缀和
    结合上面所说,对A连续子序列进行加一减一操作可以转化为对b[l]和b[r+1]进行操作。
    求出差分序列之后,原问题可以转化为将序列B从第二项开始到最后一项全部变为0的最小操作数和种数。
    这是用到贪心策略,将一个有正有负的序列进行加减最后变为0,而且题中不考虑实现过程,只要求最后结果。最小操作数就是将正数进行减操作,负数进行加操作,在[2,n]区间中任取一个正数和一个负数进行操作。最后序列剩下全正或者全负,此时种数就是剩下的数加0,相当于序列A变成的值可以为0~k,(k是剩余序列B的和)
    这里再说一下最小操作数,因为之前我这里就不是很明白,将正数减c操作就相当于序列A从当前位置一直到最后这个连续区间段都进行了c次减一操作,操作步数为c,而找一个负数与正数搭配,相当于在正数与负数这个区间内进行c次减一或者加一操作。
    最后最小的操作步数就是min(p,q)+abs(p-q),也就相当于max(p,q),种数就是abs(p-q)+1;p为序列B中正数和,q为负数和

  3. 代码

注意要用long long

#include <bits/stdc++.h>
using namespace std;
long long a[100010];
int main()
{
    long long n;
    cin>>n;
    for(int i=0; i<n; i++)
        cin>>a[i];
    long long p=0,q=0;
    for(int i=n-1; i>0; i--)
    {
        a[i]-=a[i-1];
        ///cout<<a[i]<<" ";
        if(a[i]>=0)
            p+=a[i];
        else
            q-=a[i];
    }
    long long ans=max(p,q);
    long long res=abs(p-q)+1;
    cout<<ans<<endl;
    cout<<res<<endl;
    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值