• Luogu P2101 命运石之门的选择(分治+搜索)


    P2101 命运石之门的选择

    题意

    题目描述

    在某一条不知名世界线的冈伦今天突然接到了一条(dmail),上面说世界线将会发生巨大变动,未来的他无论如何都无法扭转这种变动回到原来的世界线。而世界线变动的原因是现在的他不久后错过了与助手的约会。他约好要和助手去约会,但是在去约会之前,由于一直拖欠房租,房东大叔要求他帮忙完成一幅画的上色,然而他没有以最快的速度完成这个任务,导致他错过了与助手的约会,从而导致世界线的剧变。现在到了拯救世界的时候,由于冈伦并不擅长画画,于是他找到了同样不擅长画画的你来帮他解决这个问题(这是命运石之门的选择)。不管怎样现在拯救世界的重任交到了你的手上,而你虽然不擅长画画,但是你可以使用编程来帮助你解决这个问题。

    这幅画十分抽象:它由(N)个宽度为(1)高度为(H_i)的矩形组成,矩形并排排列,相邻的矩形间没有空隙,初始情况下每个矩形都是没有颜色的。你有一个宽度为(1)的刷子,你可以竖直或水平的刷,每次使用刷子,你的刷子都必须保证一直全部处于矩形中,即不能刷到矩形以外的地方去,当然你每次刷的时候也不能拐弯。你每刷一次,要花费(1)的时间,这和刷的长度无关,比如你可以从最左边刷到最右边(当然是不经过矩形以外的部分),这也只花费(1)的时间。你的目的是将全部的矩形都涂满颜色。请输出这个最短的时间,以便冈伦决定是自己来完成这个任务还是让你来做苦力。

    输入输出格式

    输入格式:

    (1)行:一个正整数(N),表示矩形的个数。

    接下来(N)个正整数(H_i),表示第(i)个矩形的高度。

    输出格式:

    一个整数,表示最少花费的时间。

    输入输出样例

    输入样例#1:

    5
    2 2 1 2 1
    

    输出样例#1:

    3
    

    说明

    【数据规模】

    (30\% Nleq 20, H_ileq 100)

    (60\% Nleq 100, H_ileq 1000)

    (100\% Nleq 5,000, H_ileq 10^9)

    思路

    这就是个简单的分治或者(dp)啊。 --logeadd

    完全不会分治的蒟蒻我只能做一些分治水题(qwq)

    我们对一个区间来搜索,再来一个一个区间地分下去。具体来说,我们用一个函数(dfs(l,r))来查询区间([l,r])的答案,而这个答案又可以用多个子区间([l,x_1],[x_1+1,x_2],[x_2+1,x_3]cdots [x_y+1,r])得到,这样我们一步步地分区间搜索,最后合并答案。

    那么怎么合并答案呢?对于一个区间([l,r])有一个显然的结论:先把下面的方块横着涂满,然后再竖着涂剩余的区间,所以我们可以统计出这个区间的最小高度,然后把它横着涂满,再把剩余的方块(dfs)考虑就好了。

    比方说我们有这样的一个形状:

        ■
     ■  ■■   ■
    ■■  ■■  ■■
    ■■■■■■■■■■
    ■■■■■■■■■■
    

    先把下面的方块横着涂:

        ■
     ■  ■■   ■
    ■■  ■■  ■■
    □□□□□□□□□□
    □□□□□□□□□□
    

    上方就多出来了三个小区间,再来分别(dfs)就好了。

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const LL MAXN=5e3+5;
    LL n,a[MAXN];
    LL read()
    {
        LL re=0;char ch=getchar();
        while(!isdigit(ch)) ch=getchar();
        while(isdigit(ch)) re=(re<<3)+(re<<1)+ch-'0',ch=getchar();
        return re;
    }
    LL ask(LL l,LL r)
    {
        if(l==r) return 1;
        LL re=INT_MAX;
        for(LL i=l;i<=r;i++) re=min(re,a[i]);
        for(LL i=l;i<=r;i++) a[i]-=re;
        for(LL i=l;i<=r;i++)
        {
            if(!a[i]) continue;
            LL j=i;
            while(j<=r&&a[j+1]) j++;
            re+=ask(i,j),i=j;
        }
        return min(r-l+1,re);
    }
    int main()
    {
        n=read();
        for(LL i=1;i<=n;i++) a[i]=read();
        printf("%lld",ask(1,n));
        return 0;
    }
    
  • 相关阅读:
    堆的创建、优先队列、topk、堆排序C语言实现
    HTTPS加密原理
    go shard map实现
    Python进程间通信
    TCP 半连接队列和全连接队列
    WireShark过滤语法
    TCP拥塞机制
    【企业管理实务系列】低值易耗品管理办法
    CV之Face Change:基于人工智能实现国内众多一线美女明星换脸(基于Face++输出4*106个特征点定位+融合代码、deepfake技术)
    【转发】农行银企直联XML对接socket SAP EPIC
  • 原文地址:https://www.cnblogs.com/coder-Uranus/p/9885005.html
Copyright © 2020-2023  润新知