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

    题目分析

    简单地说,题目就是让我们找出前k大的大小在l~r之间的区间。

    因为每段和弦都是连续的,而区间美妙度为所包括的音符的美妙度之和,所以可以使用前缀和来优化。

    有个最朴素的想法就是,我们把所有大小在l~r之间的区间全部抽出来排序。但这样复杂度太大了,明显无法通过,所以考虑如何优化。

    既然我们要找前k大的,一遍全找出来不好找,那么每次只找一个最优的呢?

    想一下,应该是可做且正确的,那么到底怎么找呢?

    首先对于每个点i,我们找到满足条件的且美妙度最大的j配对,然后加到一个堆里,这样首先保证了第一个从堆顶弹出的是整个序列的合法区间最大值。

    那之后怎么办呢?对于弹出的区间,它还可以扩展啊。j 是在 i+L-1 ~ i+R-1 之间的,显然对于弹出的这个区间,我们还可以把它分成 i~p1 ( i+L-1<= p1 < j )  的区间和 i~p2 ( j+1 <= p2 <= i+R-1)。

    所以我们要做的事情,就是要找能使这两个区间最大的p1和p2的位置。

    求使区间和我们会做,只要RMQ就可以,那么求使区间和最大的位置,当然也可以通过此过程做出来了。

    当然,因为我们有前缀和,所以直接可以在RMQ的过程中比较出哪个位置更优,所以RMQ中直接存使它对应的那段区间中最优的位置就行了。

    (详见代码) 

     1 #include<bits/stdc++.h>
     2 #define INTMAX 2147483647LL
     3 #define PII pair<int,int>
     4 #define MK make_pair
     5 #define re register
     6 using namespace std;
     7 typedef long long ll;
     8 const double Pi=acos(-1.0);
     9 const int Inf=0x3f3f3f3f;
    10 const int MAXN=5e5+10; 
    11 inline int read(){
    12     re int x=0,f=1,ch=getchar();
    13     while(!isdigit(ch))f=ch=='-'?-1:1,ch=getchar();
    14     while(isdigit(ch))x=x*10+ch-48,ch=getchar();
    15     return x*f;
    16 }
    17 inline ll readll(){
    18     re ll x=0,f=1,ch=getchar();
    19     while(!isdigit(ch))f=ch=='-'?-1:1,ch=getchar();
    20     while(isdigit(ch))x=x*10+ch-48,ch=getchar();
    21     return x*f;
    22 }
    23 
    24 struct Node{
    25     int ll,rr,idl,idr,val;
    26     inline bool operator <(const Node &x)const{
    27         return x.val>val;    
    28     }
    29 };
    30 
    31 ll ans;
    32 int n,k,L,R;
    33 int a[MAXN],sum[MAXN];
    34 int RMQ[MAXN][21];
    35 priority_queue<Node> q;
    36 inline int Query(int l,int r){
    37     int k=log2(r-l+1);
    38     int x=RMQ[l][k],y=RMQ[r-(1<<k)+1][k];
    39     return sum[x]>sum[y]?x:y;
    40 }
    41 int main(){
    42     n=read();k=read();L=read();R=read();
    43     for(int i=1;i<=n;++i){
    44         a[i]=read();
    45         sum[i]=sum[i-1]+a[i];
    46         RMQ[i][0]=i;
    47     }
    48     for(int j=1;(1<<j)<=n;++j)
    49         for(int i=1;i+(1<<j)-1<=n;++i){
    50             int x=RMQ[i][j-1],y=RMQ[i+(1<<(j-1))][j-1];
    51             if(sum[x]>sum[y]) RMQ[i][j]=x;
    52             else RMQ[i][j]=y;
    53         }
    54     
    55     for(int i=1;i<=n;++i)
    56         if(i+L-1<=n){
    57             int p=Query(i+L-1,min(i+R-1,n));
    58             q.push(Node{i+L-1,min(i+R-1,n),i,p,sum[p]-sum[i-1]});
    59         }
    60     for(int i=1;i<=k;++i){
    61         Node x=q.top();q.pop();
    62         ans+=(ll)x.val;
    63         if(x.ll!=x.idr){
    64             int p=Query(x.ll,x.idr-1);
    65             q.push((Node){x.ll,x.idr-1,x.idl,p,sum[p]-sum[x.idl-1]});
    66         }
    67         if(x.rr!=x.idr){
    68             int p=Query(x.idr+1,x.rr);
    69             q.push((Node){x.idr+1,x.rr,x.idl,p,sum[p]-sum[x.idl-1]});
    70         }
    71     }
    72     printf("%lld
    ",ans);
    73     return 0;
    74 }
  • 相关阅读:
    Hdu3037 Saving Beans
    bzoj3994 [SDOI2015]约数个数和
    bzoj2154 Crash的数字表格
    bzoj3529 [Sdoi2014]数表
    bzoj2820 YY的GCD
    bzoj2301 [HAOI2011]Problem b
    bzoj2440 [中山市选2011]完全平方数
    Java基础知识强化之IO流笔记20:FileOutputStream写出数据实现换行和追加写入
    Java基础知识强化之IO流笔记19:FileOutputStream的三个write方法
    Java基础知识强化之IO流笔记18:FileOutputStream写入数据
  • 原文地址:https://www.cnblogs.com/LI-dox/p/11261435.html
Copyright © 2011-2022 走看看