P2048 [NOI2010] 超级钢琴(贪心 + RMQ

#include <bits/stdc++.h>
//using int_max = 0x3f3f3f3f;
#define long_max 9223372036854775807;
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
using VI = vector<int>;
typedef unsigned long long ull;
const int mod = 1e8 - 3;
int n,k,l,r;
int a[5000010];
int s[5000010];
int st[5000010][32];
int id[5000010][32];
struct range{
    int pos,l,r,mp;
    bool operator < (range u)const{
        return s[mp] - s[pos-1] < s[u.mp] - s[u.pos-1];
    }
}tmp;



void init(){
    for(int i=1;i<=n;i++){
        st[i][0] = s[i];
        id[i][0] = i;
    }

    for(int j=1;j<=log2(n)+1;j++){
        for(int i=1;i+(1<<j)-1<=n;i++){
            if(st[i][j-1] > st[i+(1<<(j-1))][j-1]){
                st[i][j] = st[i][j-1];
                id[i][j] = id[i][j-1];
            }else{
                st[i][j] = st[i+(1<<(j-1))][j-1];
                id[i][j] = id[i+(1<<(j-1))][j-1];
            }
        }
    }
}
int query(int l, int r){
    int k = log2(r-l+1);
    if(st[l][k] > st[r-(1<<k)+1][k]){
        return id[l][k];
    }else{
        return id[r-(1<<k)+1][k];
    }

}





int main() {
    cin>>n>>k>>l>>r;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++) s[i] = s[i-1] + a[i];
    init();
    priority_queue<range> q;
    for(int i=1;i+l-1<=n;i++){
        tmp.pos = i;
        tmp.l = i+l-1;
        tmp.r = min(n,i+r-1);
        tmp.mp = query(tmp.l,tmp.r);
        //cout<<tmp.pos<<" "<<tmp.mp<<"\n";
        q.push(tmp);
    }
    ll res = 0;
    while(k--){
        auto u = q.top();
        q.pop();
        int pos = u.pos;
        int l = u.l;
        int r = u.r;
        int mp = u.mp;
        //cout<<pos<<" "<<mp<<"\n";
        res += s[mp] - s[pos-1];
        if(mp > l){
            tmp.pos = pos;
            tmp.l = l;
            tmp.r = mp-1;
            tmp.mp = query(tmp.l,tmp.r);
            q.push(tmp);
        }
        if(mp < r){
            tmp.pos = pos;
            tmp.l = mp+1;
            tmp.r = r;
            tmp.mp = query(tmp.l,tmp.r);
            q.push(tmp);

        }

    }
    cout<<res;



}

洛谷首个紫,

其实思路并不难,主要是代码实现方面脑子灵光不够

本质上来说就是RMQ问题  

当前端点为 i      选择 i+l-1 i+r-1 中的最大值,位置为k,

然后就考虑选取次大值,其中次大值一定再 i+l-1 , k -1    或者  k + 1 , i+r-1 中

简单点说,就是选择一个最大值,从最大值的位置把区间分开,构成俩个新的待选区间

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值