XTU-OJ 1451-加一

题目描述#

一个数列A={a1,a2,…,an},你可以选择一个区间[L,R],对于所有的i∈[L,R],将ai增加一。

请问最少操作多少次,可以将数列的元素变成相同的?

比如数列为{1,2,3,4},我们可以通过3次操作将所有的元素都变成4,分别取区间为[1,1],[1,2],[1,3]。

输入格式#

第一行是一个整数T(1≤T≤100),表示样例的个数。 以后每个样例占两行,第一行是整数n(1≤n≤10000),表示数列的大小。第二行是n个整数,所有整数的绝对值小于109。

输出格式#

每行输出一个样例的结果,为一个整数。

样例输入#

2
4
1 2 3 4
4
3 2 4 1

样例输出#

3
5

解题思路:把 数列 抽象看成 直方图,每个数的值,即对应 y轴的 坐标。要让所有元素都变成相同的,最简单的方法就是,从左向右扫,如果右边的数大于左边的数, 左边的数 补齐至 右边的数的大小。时间复杂度只有 O(n) .

这里使用一个新的数据结构——栈。   因为整个处理过程就是一个 入栈出栈 的过程。先把第一个数入栈,后面小于栈顶元素的值,都入栈,遇见大于栈顶元素的值,开始出栈(进行+1操作)。具体思路不细说了,找几个样例,模拟下入栈出栈的操作。

熟悉进出栈的同学,是否发现这题不用 栈 也可以写。第22行代码,ans 是不是只加 num[i] - Stack[top], 所以简化代码: 当 右数 > 左数时,ans += (num[i] - num[i-1]), 当 右数  < 左数 时,continue; 不做处理。(当然最后也要有与27行同样作用的处理)

AC代码:

#include <stdio.h>

int main()
{
    int T,n;
    scanf("%d",&T);
    while (T --)
    {
        int top = 0;
        __int64 ans = 0;
        int num[10010] = {0}, Stack[10010] = {0};
        scanf("%d",&n);
        for (int i = 0; i < n; i ++)
            scanf("%d",&num[i]);

        Stack[++top] = num[0];                                  // 第一个数 入栈
        for (int i = 1; i < n; i ++)
        {
            if (num[i] < Stack[top])    Stack[++top] = num[i];  // 如果当前数 小于 栈顶元素, 将num[i] 压入栈中
            else if (num[i] > Stack[top])                       // 如果当前数 大于 栈顶元素
            {
                ans += (num[i]-Stack[top]);                     // 前面所有 小于 num[i] 的元素, 需要 num[i]-Stack[top] 步 +1,可以全部变成 num[i]
                while (num[i] > Stack[top] && top > 0)  top --; // 小于num[i] 的元素 全部出栈
                Stack[++top] = num[i];                          // 把 num[i] 压入栈中
            }
        }
        if (top > 1)    ans += (Stack[1]-Stack[top]);           // 如果栈不为空
        printf("%I64d\n",ans);
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值