luogu P4552 [Poetize6] IncDec Sequence

P4552 [Poetize6] IncDec Sequence - 洛谷

题目描述

给定一个长度为 n n n 的数列 a 1 , a 2 , ⋯   , a n {a_1,a_2,\cdots,a_n} a1,a2,,an,每次可以选择一个区间 [ l , r ] [l,r] [l,r],使这个区间内的数都加 1 1 1 或者都减 1 1 1

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

输入格式

第一行一个正整数 n n n
接下来 n n n 行,每行一个整数,第 $i+1 $行的整数表示 a i a_i ai

输出格式

第一行输出最少操作次数
第二行输出最终能得到多少种结果

样例 #1

样例输入 #1

4
1
1
2
2

样例输出 #1

1
2

提示

对于 100 % 100\% 100% 的数据, n ≤ 100000 , 0 ≤ a i ≤ 2 31 n\le 100000, 0 \le a_i \le 2^{31} n100000,0ai231

分析

这种类型的题感觉有很多。可以把它想象成是一堆矩阵再处理,这是这类题目的一种解决方式。因为深受acwing上之前一题求最大矩阵面积的做法影响,我刚开始是把每一个矩阵左边和右边第一个比他高的矩形求出来。这样是可以划定一个区域的,可以把这些矩阵范围排列一遍。说不定可以,但是题中要求方案数,这种做法太麻烦了。

做题千万不要想到一个办法就做到底。这是我做模拟赛时得出的深痛教训,我那次打了350行代码还错了。题解比我写的简单多了。

看了一下标签,是差分。

我一想也有道理:差分仅通过改变差分数组,可以改变一个区域内的值。但我还是想不出来,于是看了题解:

第一步

因为要让所有的数字相等,那这时的差分序列也就是 a[ i ] 0 0 0 …… 总之除了第一个全是 0 。那么我们的目的就是把差分数组中所有的数都变成 0(当然除了第一个)。

我们上面有提到:改变数组一个区间内的值,只要在差分序列左边 加减,右边减加就好了。那为了找到最小方案数,我们肯定希望有现成的对吧。就是前面负后面正的,这样就是所谓的一次修改。剩下的我们就只能一次一次加或减了。用 num_add 表示正数总和,num_subtra 表示负数总和,最小方案数就是 min(num_add, q_subtra) + abs(num_add - num_subtra)

也就是 max(num_add, num_subtra)

第二步,如何求方案数

为什么会有多种方案?是由于b[ 1 ] 的值造成的。因为我们之前求最小步数是不考虑b[ 1 ]的。我们再明确一下目的:把除b[ 1 ]外的数都变成 0。所以当配对完成之后,仅有几个不是 0 ,我们将这几个不是 0 的通过加减变成 0。那么此时b[ 1 ]可以加减也可以不加减,这就是方案数的求法,搜雷瓦gin集资!那么方案数就是 abs(num_add - num_subtra)。

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

#define N 100010

long long ans1, ans2;
long long n, a[N], cf[N], bun_add = 0, num_subtra = 0;

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i ++)
    {
        cin >> a[i];
    }
    for(int i = 2; i <= n; i ++)
    {
        int c;
        c = a[i] - a[i - 1];
        if(c > 0)
            bun_add += c;
        else
            num_subtra -= c;
    }
    ans1 = max(bun_add, num_subtra);

    if(bun_add > num_subtra)
        ans2 = bun_add - num_subtra + 1;
    else
        ans2 = num_subtra - bun_add + 1;

    cout << ans1 << endl << ans2;

    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值