洛谷P4552 [Poetize6] IncDec Sequence 题解

洛谷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

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

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

这道题思路比较有趣,代码很简单但是相对来说不好想

本文比较长,建议耐心阅读(当然也可以直接 ⌘+w或者 ctrl+w

差分,常用于 O ( 1 ) O(1) O(1) 区间加减,全局询问

对于这种看上去也不是用数据结构做的题目,

考虑差分。差分数组 b i b_i bi 的定义为 b i = a i − a i − 1 b_i = a_i-a_{i-1} bi=aiai1

容易发现 a i = ∑ 1 ≤ j ≤ i b i a_i = \sum_{1 \le j \le i}b_i ai=1jibi ,值得注意的是, a 1 = b 1 a_1 = b_1 a1=b1

对于区间 [ l , r ] [l,r] [l,r] 1 1 1 的修改,只要把 b l b_l bl 加上 1 1 1 b r + 1 b_{r+1} br+1 减去 1 1 1 就可以了

然后问题就转化为了将 b 2 , b 3 , … , b n b_2,b_3,\dots,b_n b2,b3,,bn 都变成 0 0 0 的最小花费

观察差分的性质,其实每次修改就是在搬运一个 1 1 1

也就是把它从 b l b_l bl 搬到 b r + 1 b_{r+1} br+1 ,或者反过来搬

对于每个合法的修改,一定可以完成这样的操作

可以发现当 r = n r=n r=n 时会出现从外面搬过来或者搬到外面去的情况

先不急,我们先考虑 r < n r<n r<n

显然我们可以把所有的 b i < 0 b_i<0 bi<0 b j > 0 b_j >0 bj>0 配对( 2 ≤ i ≤ j ≤ n 2 \le i \le j \le n 2ijn ),然后相互抵消

可以发现这样配对消去的最小花费为 min ⁡ ( p , q ) \min(p,q) min(p,q)

其中 p = ∑ 1 ≤ i ≤ n [ b i < 0 ] ,   q = ∑ 1 ≤ i ≤ n [ b i > 0 ] p= \sum_{1 \le i \le n} [b_i<0],~q= \sum_{1 \le i \le n} [b_i>0] p=1in[bi<0], q=1in[bi>0]

这样配对也会出现最后消不完的情况,

这个时候我们就可以把它们与 n + 1 n+1 n+1 配对,或者 b 1 b_1 b1

这样的答案是 abs ⁡ ( p − q ) \operatorname{abs}(p-q) abs(pq)

则最后的答案就是 min ⁡ ( p , q ) + abs ⁡ ( p − q ) = max ⁡ ( p , q ) \min(p,q)+\operatorname{abs}(p-q)=\max(p,q) min(p,q)+abs(pq)=max(p,q)

再看第二问,其实很简单

看我们的最后一步,如果和 b 1 b_1 b1 配对 k k k 次,最后的 a i a_i ai 就会变成 b 1 + k b_1+k b1+k

所以方案数就是 abs ⁡ ( p − q ) + 1 \operatorname{abs}(p-q)+1 abs(pq)+1 (不与 b 1 b_1 b1 配对也是一种情况)

然后就好了,时间复杂度 O ( n ) O(n) O(n)

代码:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iomanip>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N (int)(1e5+15)

int n,p,q,a[N];
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n;
    for(int i=1; i<=n; i++)
        cin >> a[i];
    for(int i=2; i<=n; i++)
    {
        int c=a[i]-a[i-1];
        c>0?p+=c:q-=c;
    }
    cout << max(p,q) << '\n' << abs(p-q)+1 << '\n';
    return 0;
}

转载请说明出处

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值