差分:IncDec序列

>>题目链接

题目描述

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

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

输入格式
第一行输入正整数n。

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

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

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

数据范围
0<n≤1
0≤ai<2147483648
输入样例:

4
1
1
2
2

输出样例:

1
2

#include <algorithm>
#include <iostream>
#define Max(a, b) ((a > b) ? (a) : (b))
#define Min(a, b) ((a < b) ? (a) : (b))
using namespace std;
const int arrN{100005};
int arr[arrN];
int main(int argc, char **argv)
{
    int N;
    cin >> N;
    for (int i = 0; i != N; ++i)
        cin >> arr[i];
    auto positive{0LL}, negative{0LL};
    for (int i = N - 1; i; --i)
    {
        arr[i] -= arr[i - 1];
        if (arr[i] > 0)
            positive += arr[i];
        else if (arr[i])
            negative -= arr[i];
    }
    cout << Max(positive, negative) << endl;
    cout << abs(positive - negative) + 1 << endl;
    return EXIT_SUCCESS;
}
  • 想要得到所有数都一样,也就是要使差分序列的 2 - n 项全为 0。而第 1 项代表第一个数的大小,第 n+1 项代表第 n 个数的相反数,改变第1项或者第 n+1 项只会让数列整体变大或变小,并不影响数列相同。
  • 计算差分序列,记录差分序列中正数和负数的个数
  • 区间内都加一 / 减一也就是对差分序列中区间两侧端点加一减一,每次可以让差分序列中的两个数一个 +1 另一个 -1
  • 最佳情况是在差分序列中 2 - n 项中任取一对正负数,每次就会消掉一个正数及一个负数。这最多可以取Min( 正数个数,负数个数 )次。
  • 差一些的情况是取 2 - n 中的一个正数/负数,另一个取差分序列的第 1 项或第 n+1 项,须进行 abs( 正数个数 - 负数个数 ) 次。

因此,最小的操作次数就是 Min( 正数个数,负数个数 )+ abs( 正数个数 - 负数个数 ) ,也就是 Max( 正数个数,负数个数 ) 次;
最终可能有多少种结果,只需要计算差分序列第一项或最后一项的可能结果个数即可,如 abs( 正数个数 - 负数个数 ) 次操作全都是取第一项,那么有可能这些操作都是加一,那么第一项将有 abs( 正数个数 - 负数个数 ) + 1 种可能。
 

END

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值