BZOJ 2006: [NOI2010]超级钢琴

Description

小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的
音乐。 这架超级钢琴可以弹奏出n个音符,编号为1至n。第i个音符的美妙度为Ai,其中Ai可正可负。 一个“超级
和弦”由若干个编号连续的音符组成,包含的音符个数不少于L且不多于R。我们定义超级和弦的美妙度为其包含的
所有音符的美妙度之和。两个超级和弦被认为是相同的,当且仅当这两个超级和弦所包含的音符集合是相同的。 
小Z决定创作一首由k个超级和弦组成的乐曲,为了使得乐曲更加动听,小Z要求该乐曲由k个不同的超级和弦组成。
我们定义一首乐曲的美妙度为其所包含的所有超级和弦的美妙度之和。小Z想知道他能够创作出来的乐曲美妙度最
大值是多少。

Input

第一行包含四个正整数n, k, L, R。其中n为音符的个数,k为乐曲所包含的超级和弦个数,L和R分别是超级和弦所
包含音符个数的下限和上限。 接下来n行,每行包含一个整数Ai,表示按编号从小到大每个音符的美妙度。
N<=500,000
k<=500,000
-1000<=Ai<=1000,1<=L<=R<=N且保证一定存在满足条件的乐曲

Output

只有一个整数,表示乐曲美妙度的最大值。

Sample Input

4 3 2 3
3
2
-6
8

Sample Output

11

我擦这道题终于A了,这道题是我在好久前搞ST表时弃疗的一道题,轮ST表的正确打开方式,ST表存的可以是最大值所在的下标,那么用(i,l,r,now)表示一个状态,i表示起点,l,r表示现在这个节点所对应的区间,now代表区间最大值所在位置,区间最大值应该按s[now]-s[i-1]排序,扔到堆里,那么我们还需要考虑的是怎么用堆对这个状态进行扩展,这也就体现出来了四元组的作用,在pop掉堆顶元素后把区间分为[l,now-1]和[now+1,r]两段,取前k个就好了,此题爆int。。

code:

#define MAXN 500005
#include <bits/stdc++.h>
typedef long long ll;
int n,k,L,R,w[MAXN][21],s[MAXN],bit[21];
ll Ans;
 
struct pa{
    int pos,l,r,now;
    bool operator < (const pa&a)const{
        return s[now]-s[pos-1]<s[a.now]-s[a.pos-1];
    }
};
std::priority_queue<pa>q;
 
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    for(;ch>'9'||ch<'0';ch=getchar())if(ch=='-')f=-f;
    for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+(ch^48);
    return x*f;
}
 
inline int query(int l,int r){
    int k=0;
    while((1<<(k+1))<=r-l+1)k++;
    int x1=w[l][k],x2=w[r-bit[k]+1][k];
    return s[x1]>s[x2]?x1:x2;
}
 
int main(){
    n=read();k=read();L=read();R=read();bit[0]=1;
    for(int i=1;i<=n;i++)s[i]=s[i-1]+read();
    for(int i=1;i<=n;i++)w[i][0]=i;
    for(int i=1;i<=20;i++)bit[i]=bit[i-1]<<1;
    for(int i=1;bit[i]<=n;i++)
        for(int j=1;j<=n-bit[i]+1;j++){
            int x1=w[j][i-1],x2=w[j+bit[i-1]][i-1];
            w[j][i]=s[x1]>s[x2]?x1:x2;
        }
    for(int i=1;i<=n-L+1;i++){
        int l=i+L-1,r=std::min(i+R-1,n);
        int now = query(l,r);
        q.push((pa){i,l,r,now});
    }
    for(int i=1;i<=k;i++){
        pa lc = q.top();q.pop();
        Ans += s[lc.now]-s[lc.pos-1];
        if(lc.now+1<=lc.r)q.push((pa){lc.pos,lc.now+1,lc.r,query(lc.now+1,lc.r)});
        if(lc.now-1>=lc.l)q.push((pa){lc.pos,lc.l,lc.now-1,query(lc.l,lc.now-1)});
    }
    printf("%lld\n",Ans);
}







posted @ 2017-07-15 11:59  cooook  阅读(92)  评论(0编辑  收藏  举报