zoukankan      html  css  js  c++  java
  • P5019 铺设道路题解

    题目传送门

    一、贪心法

    题目里给的样例是(4,3,2,5,3,5),可以选择一个区间进行“填坑”操作;我们的贪心策略是:
    (a[i]>a[i-1]),计数器(sum+=a[i]-a[i-1]);

    贪心证明

    假设现在有一个坑,但旁边又有一个坑。你肯定会选择把两个同时填充,都减(1);那么小的坑肯定会被大的坑“带着”填掉。大的坑也会减少(a[i]-a[i-1])的深度,可以说是“免费的”;所以这样贪心是对的。

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long LL;
    const int N = 1000010;
    int a[N];
    
    LL ans;
    int n;
    
    int main() {
        cin >> n;
        for (int i = 1; i <= n; i++) cin >> a[i];
        for (int i = 1; i <= n; i++) if (a[i] > a[i - 1]) ans += a[i] - a[i - 1];
        cout << ans;
        return 0;
    }
    

    2、递推法

    (f[i])表示前(i)个坑所铺设的最少次数。
    那么要做的只需比较一下当前的(a[i])就是坑的深度)和(a[i-1]),分两种情况:

    1、如果(a[i]<=a[i-1]),那么在填(a[i-1])时就可以顺便把(a[i])填上,这样显然更优,所以(f[i]=f[i-1]);

    2、如果(a[i]>a[i-1]),那么在填(a[i-1])时肯定要尽量把(a[i])一块填上一部分((a[i-1])),(a[i])剩余的就单独填。

    所以,(f[i]=f[i-1]+(a[i]-a[i-1]))
    初始化(f[1]=a[1]),向后推就行了,复杂度大概是(O(n))

    #include <bits/stdc++.h>
    
    using namespace std;
    const int N = 1000010;
    //递推法
    int n, a[N];
    int f[N];   //代表前i个区域被填充好的最少次数.套路,满满的套路
    
    int main() {
        cin >> n;
        for (int i = 1; i <= n; i++) cin >> a[i];
        //递推出口,第一个有多大的坑,不能指望别人,都要靠自己来完成~
        f[1] = a[1];
        //从第2个开始进行递推
        for (int i = 2; i <= n; i++) {
            //递推式:见题解的分析过程
            if (a[i] <= a[i - 1]) f[i] = f[i - 1];
            else f[i] = f[i - 1] + (a[i] - a[i - 1]);
        }
        //输出大吉
        cout << f[n] << endl;
        return 0;
    }
    
  • 相关阅读:
    求连续序列的最大子序列和
    并查集
    分治法求最近点对
    从n个数里面选择m个数
    AcWing
    AcWing
    AcWing
    AcWing
    2017-2018 ACM-ICPC Latin American Regional Programming Contest
    2016-2017 7th BSUIR Open Programming Contest. Semifinal
  • 原文地址:https://www.cnblogs.com/littlehb/p/15037893.html
Copyright © 2011-2022 走看看