ural 2072 - Kirill the Gardener 3 详细题解 (思维+dp)

本文介绍了一个关于浇水任务的算法问题,目标是最小化浇水所需总时间。通过预先排序花朵的湿润度并采用动态规划策略来确定最佳浇水路径,确保按照湿润度递增顺序完成浇水任务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2072. Kirill the Gardener 3

Time limit: 2.0 second
Memory limit: 64 MB
Kirill the gardener has got a new task. He has to water the flowers growing on the huge flowerbed! It should be mentioned that the bed is very long and narrow at the same time. So from bird’s-eye view (and Kirill growth too) it looks like a straight line, where n points-flowers are located at regular intervals. For this job Kirill has a watering pot of infinite volume and smartwatch that shows moisture content of each flower before watering. The watering takes too much time, so the most dried flowers can die, which is unacceptable. So Kirill decided to water the flowers in order of their non-decreasing dryness. On the other hand, he wants to finish the watering as soon as possible, because there are a lot of other interesting things.
Assume that watering of one flower and walking between two neighbor flowers takes Kirill one minute. Can you figure out the time in which the young gardener will complete his job if he acts optimally? Initially Kirill stands near the leftmost flower.

Input

The first line contains an integer n (1 ≤ n ≤ 105) — it’s amount of flowers in the flowerbed. The second line contains n integers separated by spaces — it‘s moisture content of flowers given in order of their positions in the flowerbed from left to right. Moisture content is an integer from 1 up to 109 (including both).

Output

In the only line print an integer — the minimal time in which Kirill would complete watering.

Sample

input output
6
3 2 5 6 2 5
21

Notes

There is one of the possible ways to finish up in 21 minutes in the example:
  1. Go from the 1st to the 5th flower (4 minutes)
  2. Water the 5th flower (1 minute)
  3. Go from the 5th to the 2nd flower (3 minutes)
  4. Water the 2nd flower (1 minute)
  5. Go from the 2nd to the 1st flower (1 minute)
  6. Water the 1st flower (1 minute)
  7. Go from the 1st flower to the 3rd flower (2 minutes)
  8. Water the 3rd flower (1 minute)
  9. Go from the 3rd flower to the 6th flower (3 minutes)
  10. Water the 6th flower (1 minute)
  11. Go from the 6th flower to the 4th flower (2 minutes)
  12. Water the 4th flower (1 minute)


题意:有n朵花,要求按照权值递增的顺序浇水,浇水一次话一个时间,走一个单位长度花费一个单位时间

思路:第一步,肯定是从1走到 最近最低权值的位置,然后一直往右走,你会发现,同一权值的肯定是从两头开始浇水,就算你从中间教过去,还是要走到一头再从一头走回到另一头,所以就很简单了,dp1代表从左面进入的,dp2代表从右面进入的,每个转移方程式就是这一段要走的距离r[i]-l[i],加上上面从左面走的情况 或者上面从右面走的情况,算个水题吧。。比赛的时候,我没敲这题。。(赛后20+分钟就过了,而且觉得代码写的很漂亮~嘻嘻。)

另外,其实不用dp数组记录,用几个变量记录就好了。。你会发现只与前面一个状态有关,所以用变量记录,这也是建立在你很理解这个题了,很清楚怎么转移了,差不多懂了。

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
struct node
{
    int x, id;
    node() {}
    node(int xx, int ii) : x(xx), id(ii){}
    bool operator < (const node &a) const
    {
        if(x == a.x) return id < a.id;
            else return x < a.x;
    }
}a[maxn];
ll l[maxn], r[maxn], dp1[maxn], dp2[maxn];
int main()
{
    int n, index;
    while(~scanf("%d", &n))
    {
        memset(dp1, 0, sizeof(dp1));
        memset(dp2, 0, sizeof(dp2));
        memset(l, 0, sizeof(l));
        memset(r, 0, sizeof(r));
        index = 1;
        for(int i = 1; i <= n; i++)
            scanf("%d", &a[i].x), a[i].id = i;
        sort(a+1, a+1+n);
        l[index] = 1;
        r[index] = 1;
        for(int i = 2; i <= n; i++) //处理出所有的线段
        {
            if(a[i].x != a[i-1].x)
                r[index] = a[i-1].id, l[++index] = a[i].id;  
            if(i == n) r[index] = a[i].id;
        }
        l[0] = r[0] = 1;
        for(int i = 1; i <= index; i++)
        {
            dp1[i] = r[i]-l[i]+min(dp1[i-1]+abs(l[i]-r[i-1]), dp2[i-1]+abs(l[i]-l[i-1]));
            dp2[i] = r[i]-l[i]+min(dp1[i-1]+abs(r[i]-r[i-1]), dp2[i-1]+abs(r[i]-l[i-1]));
        }
        printf("%lld\n", min(dp1[index], dp2[index])+n);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值