zoukankan      html  css  js  c++  java
  • bzoj2006: [NOI2010]超级钢琴

    题意:给一个序列(n<=500000),要求选定k个不同区间,使得区间长度在L,R之间,并使得k个区间和之和最大,输出这个最大值。

    刚拿到题的时候想的是,对于每个点,如果以它开头,那么之后的L-1个一定被选,剩下的R-L个可选,对这一部分进行最大前缀和就好啦!用主席树搞搞,建树的时候维护下就好了。

    但有个问题,以这个区间为开头的情况不止一种,这种做法确实能求出以它开头的最大值,那次大值,k大值呢?这也是有可能计入答案的。所以不行。

    正解是,对于一个位置,如果我们考虑以它结尾,这个区间等于它的前缀和减去前面一个位置的前缀和,其中位置i满足i离这个位置不小于L不超过R。对于这个位置,我们只需要找这个区间内的区间k大,用这个位置前缀和减掉就好了,然后去求区间k+1大。放入一个堆中取k次就好。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 500005
     4 #define LL long long
     5 inline int read(){
     6     int x=0,f=1; char a=getchar();
     7     while(a<'0' || a>'9') {if(a=='-') f=-1; a=getchar();}
     8     while(a>='0' && a<='9') x=x*10+a-'0',a=getchar();
     9     return x*f;
    10 }
    11 LL sum[N];
    12 struct data{
    13     int num,k;LL val;
    14     bool operator < (const data& w)const{
    15         return val<w.val;
    16     }
    17 }t;
    18 priority_queue<data>q;
    19 namespace Chairman_Tree{
    20     int root[N],size;
    21     struct ct{
    22         int son[2],sz;
    23     }tr[20000005];
    24     void insert(int x,int& y,LL l,LL r,LL v){
    25         y=++size; tr[y].sz=tr[x].sz+1;
    26         if(l==r) return;
    27         memcpy(tr[y].son,tr[x].son,sizeof(tr[y].son));
    28         int mid=(l+r)>>1;
    29         if(mid>=v) insert(tr[x].son[0],tr[y].son[0],l,mid,v);
    30         else insert(tr[x].son[1],tr[y].son[1],mid+1,r,v);
    31     }
    32     LL query(int x,int y,LL l,LL r,int k){
    33         if(tr[y].sz-tr[x].sz<k) return 1e9;
    34         if(l==r) return l;
    35         int mid=(l+r)>>1,s=tr[tr[y].son[0]].sz-tr[tr[x].son[0]].sz;
    36         if(k<=s) return query(tr[x].son[0],tr[y].son[0],l,mid,k);
    37         else return query(tr[x].son[1],tr[y].son[1],mid+1,r,k-s);
    38     }
    39 }
    40 #define CT Chairman_Tree
    41 #define L -500000005
    42 #define R 500000005
    43 int main(){
    44     int n=read(),k=read(),l=read(),r=read();
    45     LL ans=0; CT::insert(0,CT::root[0],L,R,0);
    46     for(int i=1;i<=n;i++) sum[i]=sum[i-1]+read();
    47     for(int i=1;i<=n;i++) CT::insert(CT::root[i-1],CT::root[i],L,R,sum[i]);
    48     for(int i=l;i<=n;i++){
    49         int ri=i-l,le=i-r-1;
    50         LL tmp;
    51         if(le<0) tmp=CT::query(0,CT::root[ri],L,R,1);
    52         else tmp=CT::query(CT::root[le],CT::root[ri],L,R,1);
    53         q.push((data){i,1,sum[i]-tmp});
    54     }
    55     while(k--){
    56         t=q.top(); q.pop();
    57         ans+=t.val;
    58         int ri=t.num-l,le=t.num-r-1; LL tmp;
    59         if(le<0) tmp=CT::query(0,CT::root[ri],L,R,t.k+1);
    60         else tmp=CT::query(CT::root[le],CT::root[ri],L,R,t.k+1);
    61         q.push((data){t.num,t.k+1,sum[t.num]-tmp});
    62     }
    63     cout<<ans;
    64     return 0;
    65 }
  • 相关阅读:
    UVa 1151 Buy or Build【最小生成树】
    UVa 216 Getting in Line【枚举排列】
    UVa 729 The Hamming Distance Problem【枚举排列】
    HDU 5214 Movie【贪心】
    HDU 5223 GCD
    POJ 1144 Network【割顶】
    UVa 11025 The broken pedometer【枚举子集】
    HDU 2515 Yanghee 的算术【找规律】
    Java基本语法
    Java环境变量,jdk和jre的区别,面向对象语言编程
  • 原文地址:https://www.cnblogs.com/enigma-aw/p/6247889.html
Copyright © 2011-2022 走看看