zoukankan      html  css  js  c++  java
  • 洛谷 P1969 积木大赛

    题目描述

    春春幼儿园举办了一年一度的“积木大赛”。今年比赛的内容是搭建一座宽度为n的大厦,大厦可以看成由n块宽度为1的积木组成,第i块积木的最终高度需要是hi。

    在搭建开始之前,没有任何积木(可以看成n块高度为 0 的积木)。接下来每次操作,小朋友们可以选择一段连续区间[l, r],然后将第第 L 块到第 R 块之间(含第 L 块和第 R 块)所有积木的高度分别增加1。

    小 M 是个聪明的小朋友,她很快想出了建造大厦的最佳策略,使得建造所需的操作次数最少。但她不是一个勤于动手的孩子,所以想请你帮忙实现这个策略,并求出最少的操作次数。

    输入输出格式

    输入格式: 

    输入文件为 block.in

    输入包含两行,第一行包含一个整数n,表示大厦的宽度。

    第二行包含n个整数,第i个整数为hi 。 

    输出格式: 

    输出文件为 block.out

    仅一行,即建造所需的最少操作数。 

    输入输出样例

    5
    2 3 4 1 2
    输出样例#1:
    5

    说明

    【样例解释】

    其中一种可行的最佳方案,依次选择

    [1,5] [1,3] [2,3] [3,3] [5,5]

    【数据范围】

    对于 30%的数据,有1 ≤ n ≤ 10;

    对于 70%的数据,有1 ≤ n ≤ 1000;

    对于 100%的数据,有1 ≤ n ≤ 100000,0 ≤ hi≤ 10000。

    思路:

      这道题很深,你可以做的很麻烦,也可以做的很简单,你都认为那是正解。

      我就想了很多思路,然后用了最麻烦的方法。。但至少练习了一下倍增

      1递归去做  

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<algorithm>
    #include<vector>
    #include<cmath>
    #include<ctime>
    using namespace std;
    const int N=100009;
    int a[N];
    int n;
    int f1[N][20],F;//zhi
    int f2[N][20];//where
    long long ans;
    inline void work(int L,int R,int tot)
    {
        if(L==R)
        {
            ans+=a[L]-tot;
            return ;
        }
        if(L>R)    return ;
        int F=(log2(R-L+1)/log2(2));
        int minn,minw;
        if(f1[L][F]<=f1[R-(1<<F)+1][F])
            minn=f1[L][F],minw=f2[L][F];
        else 
            minn=f1[R-(1<<F)+1][F],minw=f2[R-(1<<F)+1][F];
        ans+=minn-tot;
        work(L,minw-1,minn);work(minw+1,R,minn);
        return ;
    }
    int main()
    {
        
        scanf("%d",&n);
        F=(log2(n)/log2(2));
        for(int i=1;i<=n;i++)    
        {
            scanf("%d",&a[i]);
            f1[i][0]=a[i];
            f2[i][0]=i;
        }
        for(int j=1;j<=F;j++)
        for(int i=1;i<=n;i++)
        {
            if(f1[i][j-1]<=f1[i+(1<<(j-1))][j-1])
                f1[i][j]=f1[i][j-1],f2[i][j]=f2[i][j-1];
            else 
                f1[i][j]=f1[i+(1<<(j-1))][j-1],f2[i][j]=f2[i+(1<<(j-1))][j-1];
        }
        work(1,n,0);
        cout<<ans<<endl;
        return 0;    
    }
    倍增,递归

      2有点贪心吧,我也说不清

      就是如果后一个比前个,大就要加它们的差。

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<algorithm>
    #include<vector>
    #include<cmath>
    #include<ctime>
    using namespace std;
    const int N=100009;
    int x,last,n;
    long long ans;
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&x);
            if(x>last)    ans+=x-last;
            last=x;
        }
        cout<<ans;
        return 0;
    }  
    贪心
  • 相关阅读:
    51nod 1494 选举拉票 | 线段树
    51nod 1295 XOR key | 可持久化Trie树
    Codeforces 438D (今日gg模拟第二题) | 线段树 考察时间复杂度的计算 -_-|||
    51nod 1563 坐标轴上的最大团(今日gg模拟第一题) | 线段覆盖 贪心 思维题
    良心的可持久化线段树教程
    51nod 1593 公园晨跑 | ST表(线段树?)思维题
    51nod 1595 回文度 | 马拉车Manacher DP
    51nod 1522 上下序列
    胡小兔的OI日志3 完结版
    51nod 1510 最小化序列 | DP 贪心
  • 原文地址:https://www.cnblogs.com/CLGYPYJ/p/7686420.html
Copyright © 2011-2022 走看看