增减序列

增减序列

题目描述

在这里插入图片描述


题意解释

对区间 [ L , R ] [L,R] [L,R]内的序列都进行加1或者减1操作,使得 a 1 , a 2 , ⋯   , a n a_1,a_2,\cdots ,a_n a1,a2,,an都是相同的。问题1:至少需要几步操作,可以使得 a 1 , a 2 , ⋯   , a n a_1,a_2,\cdots ,a_n a1,a2,,an都是相同的。问题2:在这种最少操作步数的前提下,可以得到多少种序列。


分析

  • b[1]=a[1]
  • b[2]=a[2]-a[1]
  • b[3]=a[3]-a[2]
  • $\cdots \cdots \cdots $
  • b[n]=a[n-1]-a[n]

由此可见,如果b[2]为0,那么a[2]=a[1];如果b[3]为0,那么a[3]=a[2], ⋯ \cdots ;如果b[n]为0,那么a[n-1]=a[n]。因此,如果b[2],b[3],b[4], ⋯ \cdots ,b[n]都为0,那么a[1]=a[2]=a[3]= ⋯ \cdots =a[n]。那么a序列就都是相同的了。也就是说,要想让a序列都相同的话,那么就必须让b[2],b[3], ⋯ \cdots ,b[n]都为0,然后b[1]=a[1]可以任意选择。因此题目说了 0 ≤ a i ≤ 2147483648 0\leq a_i\leq2147483648 0ai2147483648。所以a[1]可以从 0 0 0 2147483648 2147483648 2147483648范围内任意选择一个数,那么最终a序列就全都是这个数。

因此,题目问的问题就可以翻译为:

问题1:至少需要操作多少次,使得 b 2 b_2 b2~ b n b_n bn 都为0

问题2:在最少操作步数的前提下, b 1 b_1 b1 有多少种值

由差分意义可知,要想让 a L a_L aL~ a R a_R aR都加1或减1    ⟺    b L + = 1 , b R + 1 − = 1 \iff b_L+=1,b_{R+1}-=1 bL+=1,bR+1=1。因为对于差分数组b来说,假设我们要对数列a的某个区间 [ L , R ] [L,R] [L,R]都进行加上常数c,那么就会写成 b [ L ] + = c , b [ R + 1 ] − = c b[L]+=c,b[R+1]-=c b[L]+=cb[R+1]=c,因此会用到 b R + 1 b_{R+1} bR+1,也就是说对数列 a 1 , a 2 , ⋯   , a n a_1,a_2,\cdots ,a_n a1,a2,,an都要进行加1或减1操作,那么可以写成 b [ 1 ] + = 1 , b [ n + 1 ] − = 1 b[1]+=1,b[n+1]-=1 b[1]+=1,b[n+1]=1,因此,差分数组b是从 b 1 b_1 b1~ b n + 1 b_{n+1} bn+1,共有 n + 1 n+1 n+1项,但是序列a它是有 n n n项。

题目对序列a的操作,相当于每次可以从差分数组b选出 b 1 , b 2 , ⋯   , b n + 1 b_1,b_2,\cdots ,b_{n+1} b1,b2,,bn+1中的任意两个数,一个数加1,另一个数减1。目标是把 b 2 , b 3 , ⋯   , b n b_2,b_3,\cdots ,b_n b2,b3,,bn全变成0,最终得到的数列a就是就 n n n b 1 b_1 b1构成的。


核心思路

首先要明确目标: b 2 , b 3 , ⋯   , b n b_2,b_3,\cdots ,b_n b2,b3,,bn都为0,然后 b 1 b_1 b1随意。

从差分数组 b 1 , b 2 , ⋯   , b n b_1,b_2,\cdots ,b_n b1,b2,,bn中任意选择两个数的方法可以分为四类:

  • ( 1 ) (1) (1) 选择 b i b_i bi b j b_j bj,其中 2 ≤ i , j ≤ n 2\leq i,j\leq n 2i,jn。这种操作会改变 b 2 , b 3 , ⋯   , b n b_2,b_3,\cdots ,b_n b2,b3,,bn中的任意两个数的值(假设选择了 b 5 b_5 b5 b 10 b_{10} b10,那么就可以对 b 5 b_5 b5进行加1或减1操作,对 b 10 b_{10} b10进行减1或加1操作)。应该在保证 b i b_i bi b j b_j bj一正一负的前提下,尽量多地最好采取这种操作,这样会更接近目标。我们每一次选取 b i b_i bi b j b_j bj,这两个数一定是一正一负(最好是绝对值相同,比如 b i = 5 , b j = − 5 b_i=5,b_j=-5 bi=5,bj=5)。为什么呢?因为我们想要让 b x ( 2 ≤ x ≤ n ) b_x(2\leq x\leq n) bx(2xn)为0而且是最少步数,那么假设我们选取的 b i b_i bi是正数, b j b_j bj是负数,那么让正数减1,负数+1,这样可以同时让正数向 0 0 0逼近,负数向 0 0 0逼近,是均衡的,会更块地让这两个数都接近0。假设我们选取的 b i b_i bi b j b_j bj都是正数(或者负数),那么让这两个正数同时减1,虽然是同时减1,但是这两个正数逼近0的速率不同,可能需要很多操作步数。因此,每次我们都要尽量让 b i b_i bi b j b_j bj同时选择正数和负数,这样才能更快并且步数少地接近0。如果没有正数和负数可以搭配了,比如剩下的 b x b_x bx都是正数或者都是负数,那么我们可以选出 b 1 b_1 b1 b n + 1 b_{n+1} bn+1,因为这两个数都并不影响 b 2 , b 3 , ⋯   , b n b_2,b_3,\cdots ,b_n b2,b3,,bn,这两个不管怎么操作都不会影响数的修改。

在这里插入图片描述

  • $(2) $ 选择 b 1 b_1 b1 b j b_j bj,其中 2 ≤ j ≤ n 2\leq j\leq n 2jn,那么就是让 b 1 b_1 b1加1(或减1), b 2 b_2 b2~ b n b_n bn中的某一个减1(或加1)。也就是说这种情况它只能让$b_2   ~  b_n 中 的 某 一 个 中的某一个 b_x$加1(或减1),只能修改差分数组中的一个数而已。

在这里插入图片描述

  • ( 3 ) (3) (3) 选择 b i b_i bi b n + 1 b_{n+1} bn+1,其中 2 ≤ i ≤ n 2\leq i\leq n 2in,那么就是让 b n + 1 b_{n+1} bn+1加1(或减1), b 2 b_2 b2~ b n b_n bn中的某一个减1(或加1).也就是说这种情况它只能让 b 2 b_2 b2 ~ b n b_n bn中的某一个 b x b_x bx加1(或减1),只能修改差分数组中的一个数。

  • 在这里插入图片描述

  • ( 4 ) (4) (4) 选择 b 1 b_1 b1 b n + 1 b_{n+1} bn+1。这种情况毫无意义。因为它并不会改变 b 2 , b 3 , ⋯   , b n b_2,b_3,\cdots ,b_n b2,b3,,bn,这与我们的目标无关,相当于浪费了一次操作步数,一定步数最优解,因此这种情况不选,毫无意义。

因此,现在的核心想法就是如何运用上述的三种操作,可以更快用更少的操作取完成我们的目标。从直觉上看,我们应该多用第一种操作,因为第一种操作它一次可以改变差分数组的两个数,而第二、三种操作,它一次只能改变差分数组中的一个数。

b 2 , b 3 , ⋯   , b n b_2,b_3,\cdots ,b_n b2,b3,,bn中正数总和为p,负数总和的绝对值为q。首先以正负数配对的方式尽量执行操作1,可执行 m i n ( p , q ) min(p,q) min(p,q)次,假设 p ≥ q p\geq q pq,也就是说负数个数比较少一些,正数个数比较多一些,那么就以负数个数为准,因为最少的负数个数决定了正负数配对的次数。因为正数个数比较多,所以此时差分数组中还剩下== ∣ p − q ∣ |p-q| pq个正数,而没有负数了,即还剩下 ∣ p − q ∣ |p-q| pq个未配对。那么就可以对剩下的这 ∣ p − q ∣ |p-q| pq个正数选择与 b 1 b_1 b1 b n + 1 b_{n+1} bn+1配对,即进行操作2或操作3。因此,最少的操作步数就是: m i n ( p , q ) + ∣ p − q ∣ min(p,q)+|p-q| min(p,q)+pq。由数学公式可以知道,其实 m i n ( p , q ) + ∣ p − q ∣    ⟺    m a x ( p , q ) min(p,q)+|p-q|\iff max(p,q) min(p,q)+pqmax(p,q)==。

因为我们已经求出了最少步数,那么在最少步数的前提下,如何求出不同种的序列呢?

首先要明确,不同种序列是由 b 1 b_1 b1决定的。还剩下 ∣ p − q ∣ |p-q| pq个未配对,这剩下的 ∣ p − q ∣ |p-q| pq个数既可以和 b 1 b_1 b1配对,也可以和 b n + 1 b_{n+1} bn+1配对,那么 b 1 b_1 b1可以分配 0 , 1 , 2 , ⋯   , ∣ p − q ∣ 0,1,2,\cdots ,|p-q| 0,1,2,,pq个,与之对应的 b n + 1 b_{n+1} bn+1可以分配 ∣ p − q ∣ , ∣ p − q ∣ − 1 , ⋯   , 0 |p-q|,|p-q|-1,\cdots ,0 pq,pq1,,0个,共有 ∣ p − q ∣ + 1 |p-q|+1 pq+1种情况。即进行操作2,由于操作2会改变 b 1 b_1 b1的值,因此,如果我们进行 ∣ p − q ∣ + 1 |p-q|+1 pq+1次操作2,就会修改 ∣ p − q ∣ + 1 |p-q|+1 pq+1 b 1 b_1 b1,那么就会得到 ∣ p − q ∣ + 1 |p-q|+1 pq+1 b 1 b_1 b1。所以在求出了最少步数的这种前提下,可以得到 ∣ p − q ∣ + 1 |p-q|+1 pq+1种不同的a序列。


代码

#include<iostream>
#include<algorithm>
using namespace std;
const int N=100010;
typedef long long LL;
int a[N],b[N];	//a是数列a,b是差分数组
int main()
{
    int n;
    scanf("%d",&n);
    //输入数列a
    for(int i=1;i<=n;i++)
    scanf("%d",&a[i]);
    //构造差分数组b
    for(int i=1;i<=n;i++)
    b[i]=a[i]-a[i-1];
    //p是b2,b3...,bn中正数总和	q是b2,b3...,bn中负数总和的绝对值
    LL p=0,q=0;
    for(int i=2;i<=n;i++)
    {
        if(b[i]>0)	//统计差分数组中正数的总和
        p+=b[i];
        else	//统计差分数组中负数绝对值的总和
        q-=b[i];
    }
    //最少的操作步数就是min(p,q)+|p-q|,也就是max(p,q)
    cout <<max(p,q)<<endl;
    //不同种a序列 就是|p-q|+1
    cout <<abs(p-q)+1<<endl;
    return 0;
}

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卷心菜不卷Iris

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值