zoukankan      html  css  js  c++  java
  • P2048 [NOI2010] 超级钢琴 题解

    \(Description\)

    Luogu传送门

    \(Solution\)

    早就想做这道 P2048 了,但是之前太菜了,不会 QwQ

    RMQ + 前缀和 + 堆

    显然要做一个前缀和,但是做完前缀和之后暴力枚举区间显然是不行的。

    考虑一下我们到底要计算什么:

    对于一个点 \(u\),我们要计算 \(\max\{sum_t - sum_{u - 1}\}\ (\ t \in [u + L - 1, u + R - 1])\)

    \(sum_{u - 1}\) 是固定的,所以我们要使用某种方法快速计算出 \(\max\{sum_t\}\ \ (t \in [u + L - 1, u + R - 1])\)

    这时候 \(RMQ\) 就闪亮登场了。

    关于 \(RMQ\) 不会的话去看其他 dalao 的博客吧=-=

    简单来说就是开个数组 \(f_{i, k}\) 表示从 \(i\) 开始长度为 \(2^k\) 的区间中的(最大值/最小值)。

    然后预处理一下这个数组,查询的时候就可以 \(O(1)\) 查询了。

    然后类似于 异或粽子 那题,开个大根堆,每次取出当前堆顶,插入次大的值。

    重复上述操作即可。

    \(Code\)

    #include <bits/stdc++.h>
    #define ll long long
    
    using namespace std;
    
    namespace IO{
        inline int read(){
            int x = 0, f = 1;
            char ch = getchar();
            while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
            while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
            return x * f;
        }
    
        template <typename T> inline void write(T x){
            if(x < 0) putchar('-'), x = -x;
            if(x > 9) write(x / 10);
            putchar(x % 10 + '0');
        }
    }
    using namespace IO;
    
    const int N = 5e5 + 10;
    int n, k, L, R;
    int f[N][20];
    ll sum[N];
    
    inline void init(){
        for(int i = 1; i <= n; ++i) f[i][0] = i;
        for(int j = 1; (1 << j) <= n; ++j)
            for(int i = 1; i + (1 << j) - 1 <= n; ++i){
                int x = f[i][j - 1], y = f[i + (1 << (j - 1))][j - 1];
                f[i][j] = sum[x] > sum[y] ? x : y;
            }
    }
    
    inline int query(int l, int r){
        int k = log2(r - l + 1);
        int x = f[l][k], y = f[r - (1 << k) + 1][k];
        return sum[x] > sum[y] ? x : y;
    }
    
    struct node{
        int u, l, r, t;
        node(int _u = 0, int _l = 0, int _r = 0){
            u = _u, l = _l, r = _r, t = query(_l, _r);
        }
    
        inline bool operator < (const node &b) const{
            return sum[t] - sum[u - 1] < sum[b.t] - sum[b.u - 1];
        }
    };
    priority_queue <node> q;
    
    int main(){
        n = read(), k = read(), L = read(), R = read();
        for(int i = 1; i <= n; ++i) sum[i] = sum[i - 1] + read();
        init();
        for(int i = 1; i <= n; ++i)
            if(i + L - 1 <= n) q.push(node{i, i + L - 1, min(i + R - 1, n)});
        ll ans = 0;
        while(k--){
            node now = q.top(); q.pop();
            ans += sum[now.t] - sum[now.u - 1];
            if(now.t != now.l) q.push(node{now.u, now.l, now.t - 1});
            if(now.t != now.r) q.push(node{now.u, now.t + 1, now.r});
        }
        write(ans), puts("");
        return 0;
    }
    

    \[\_EOF\_ \]

  • 相关阅读:
    MySQL 8.0.14版本新功能详解
    Uncaught TypeError: Right-hand side of 'instanceof' is not an object
    程序员快速技术提升之道
    Windows 10 cmd命令符的使用
    数据千万条,备份第一条:VFEmail被擦除所有数据面临关停
    netty-socketio 示例代码
    idea中 在接口中如何直接跳转到该接口的是实现类中?
    perl DBD处理超时问题
    springboot 启动配置文件配置
    Office Word 发布文章到博客园
  • 原文地址:https://www.cnblogs.com/xixike/p/15746049.html
Copyright © 2011-2022 走看看