• 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 }
  • 相关阅读:
    SSH 远程执行任务
    redmine + git
    progit-cn
    bash keys
    性能优化挑战重重,鲲鹏 HPC 如何突破算力桎梏?
    基因组实现自动AI建模,华为云助力科研人员探索生命奥秘
    【华为云技术分享】从零搭建一个灰度发布环境
    全面拥抱 FastApi — 多应用程序项目结构规划
    【华为云技术分享】物体检测yolo3算法 学习笔记(1)
    【华为云技术分享】物体检测yolo3算法 学习笔记2
  • 原文地址:https://www.cnblogs.com/enigma-aw/p/6247889.html
Copyright © 2020-2023  润新知