BZOJ2006:[NOI2010]超級鋼琴——題解

https://www.lydsy.com/JudgeOnline/problem.php?id=2006php

https://www.luogu.org/problemnew/show/P2048#subios

小Z是一個小有名氣的鋼琴家,最近C博士送給了小Z一架超級鋼琴,小Z但願可以用這架鋼琴創做出世界上最美妙的音樂。git

這架超級鋼琴能夠彈奏出n個音符,編號爲1至n。第i個音符的美妙度爲Ai,其中Ai可正可負。spa

一個「超級和絃」由若干個編號連續的音符組成,包含的音符個數很多於L且很少於R。咱們定義超級和絃的美妙度爲其包含的全部音符的美妙度之和。兩個超級和絃被認爲是相同的,當且僅當這兩個超級和絃所包含的音符集合是相同的。code

小Z決定創做一首由k個超級和絃組成的樂曲,爲了使得樂曲更加動聽,小Z要求該樂曲由k個不一樣的超級和絃組成。咱們定義一首樂曲的美妙度爲其所包含的全部超級和絃的美妙度之和。小Z想知道他可以創做出來的樂曲美妙度最大值是多少。blog

O(n^2)很好想,確定會T。get

但事實上咱們只須要區間前k大便可,因此不必算出O(n^2)的區間和。博客

思考對於每一個左端點l,有一個r使得[l,r]區間和最大,咱們把這些值都存起來取最大就是全部區間和的最大值,而後把它彈出。string

繼續對於彈出的元素也能夠貢獻它的第二大,第三大……分別知足的r,咱們依次加進去。it

一種直觀的想法是主席樹維護,而後翻了題解開始舔st表。

事實上咱們在[L,R]找到的最大值對應的r,其第二大對應的r必定是[L,r-1]和[r+1,R]最大值對應的r,用st表維護一遍便可。

(然而我菜……我根本沒想到第三段話的內容TAT)

(果真人傻就該多刷題)

#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=5e5+5;
const int B=19;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
int n,k,L,R;
int s[N],lg[N],dp[N][B+3];
struct data{
    int l,r,w,L,R;
    bool operator <(data b)const{
        return w<b.w;
    }
};
priority_queue<data>q;
inline int qpow(int a){return 1<<a;}
void st(){
    for(int i=1;i<=n;i++){
        dp[i][0]=i;
        lg[i]=lg[i-1];
        if((1<<lg[i]+1)==i)lg[i]++;
    }
    for(int j=1;j<=lg[n];j++){
        for(int i=1;i<=n;i++){
            if(i+qpow(j)-1>n)break;
            int l=dp[i][j-1],r=dp[i+qpow(j-1)][j-1];
            if(s[l]>s[r])dp[i][j]=l;
            else dp[i][j]=r;
        }
    }
}
inline int getmax(int l,int r){
    int len=r-l+1,h=lg[len];
    int l1=dp[l][h],r1=dp[r-qpow(h)+1][h];
    if(s[l1]>s[r1])return l1;
    else return r1;
}
int main(){
    n=read(),k=read(),L=read(),R=read();
    for(int i=1;i<=n;i++)s[i]=s[i-1]+read();
    st();
    for(int i=1;i+L-1<=n;i++){
        int j=getmax(i+L-1,min(i+R-1,n));
        q.push((data){i,j,s[j]-s[i-1],i+L-1,min(i+R-1,n)});
    }
    ll ans=0;
    while(k--){
        data tmp=q.top();q.pop();
        ans+=tmp.w;
        int i=tmp.l,j=tmp.r;
        if(tmp.L<=j-1){
            int t=getmax(tmp.L,j-1);
            q.push((data){i,t,s[t]-s[i-1],tmp.L,j-1});
        }
        if(j+1<=tmp.R){
            int t=getmax(j+1,tmp.R);
            q.push((data){i,t,s[t]-s[i-1],j+1,tmp.R});
        }
    }
    printf("%lld\n",ans);
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

 +本文做者:luyouqi233。               +

 +歡迎訪問個人博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

相關文章
相關標籤/搜索