NOIP2018D1T1 铺设道路

时间:2024-07-21 09:37:26

原题:NOIP2013D1T1 积木大赛

题目地址:P5019 铺设道路

思路:玄学瞎搞

将每块区域插入一个小根堆,这里的小根堆用优先队列实现,即运用一个 \(pair\) , \(first\) 为 \(-d_i\) , \(second\) 为 \(i\)

每次取出堆顶,与上一次取出的数作差得到 \(d\) (如果是第一个数则上一个数为0), \(d\) 即为从上一个深度还需向下多深到现在的深度

而这部分所需的天数为 \(d×num\) , \(num\) 为这部分深度被分成了多少个部分,即填充1层所需的天数

开始时 \(num\) 为1,初始化一个bool数组 \(v\) 为 \(false\) , \(v_0=v_{n+1}=true\)

每次取出堆顶的 \(second\) 即为一个分割点, \(v_{second}=true\)

此时有三种情况:

若 \(v_{second-1}==true\) 且 \(v_{second+1}==true\) ,则 \(num--\) ;

若 \(v_{second-1}==false\) 且 \(v_{second+1}==false\) ,则 \(num++\) ;

否则, \(num\) 不变。

总时间复杂度为 \(O(n\ log\ n)\)

考场AC代码:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 100006;
int n, d[N];
bool v[N];
ll ans = 0;
priority_queue<pair<int, int> > pq;

int main() {
    //freopen("road.in", "r", stdin);
    //freopen("road.out", "w", stdout);
    scanf("%d", &n);
    while (pq.size()) pq.pop();
    for (int i = 1; i <= n; i++) {
        scanf("%d", &d[i]);
        pq.push(make_pair(-d[i], i));
    }
    int num = 1, k = 0;
    memset(v, 0, sizeof(v));
    v[0] = v[n+1] = 1;
    while (pq.size()) {
        int x = pq.top().second;
        pq.pop();
        ans += (ll)(d[x] - k) * num;
        k = d[x];
        v[x] = 1;
        if (v[x+1] && v[x-1]) num--;
        else if (!v[x+1] && !v[x-1]) num++;
    }
    printf("%lld\n", ans);
    return 0;
}

PS:好像没看到跟我相同做法的......