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

    bzoj2006[NOI2010]超级钢琴

    题意:

    超级钢琴可以弹奏出n个音符,编号为1至n。第i个音符的美妙度为Ai,其中Ai可正可负。一个“超级和弦”由若干个编号连续的音符组成,包含的音符个数不少于L且不多于R,其美妙度为包含的所有音符的美妙度之和。两个超级和弦被认为是相同的,当且仅当这两个超级和弦所包含的音符集合是相同的。现需创作一首由k个不同的超级和弦组成的乐曲。定义一首乐曲的美妙度为其所包含的所有超级和弦的美妙度之和。求能够创作出来的乐曲美妙度最大值是多少。

    题解:

    乍一看很难,实际上是可做的。题目实际上是求前k大的区间。设计状态(x,l,r,y,z)表示左端点为x,右端点在l到r之间的区间最大值为y且最大的区间右端点为z。预处理求出所有(i,i+L-1,i+R-1)的状态放入按y排的优先队列。枚举k次,每次从优先队列中取出最大的累加它的y,然后这个区间不能取了,所以求(x,l,z-1)和(x,z+1,r)再放入优先队列。怎么求这些状态?因为做端点是固定的,所以求区间s[l..r]的RMQ就行了,预处理时顺便求出f数组以便于求RMQ的时候用倍增。反思:我觉得RMQ的倍增和LCA的倍增是一样的,所以就用了求LCA的倍增写法,过倒是能过,速度不知道会不会慢一点。

    代码:

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #include <queue>
     5 #define inc(i,j,k) for(int i=j;i<=k;i++)
     6 #define INF 0x3fffffff
     7 using namespace std;
     8 
     9 struct node{
    10     int f,l,r,a1,a2;
    11     bool operator < (const node&a)const{
    12         return a1<a.a1;
    13     }
    14 };
    15 int n,k,l,r,f1[600000][20],f2[600000][20],s[600000];
    16 priority_queue <node> q;
    17 void add(int f,int l,int r){
    18     if(l==r){q.push((node){f,l,r,s[l]-s[f-1],l}); return;}
    19     if(l>r)return;
    20     int a1=r-l,a2=-INF,a3,a4=l;
    21     for(int i=0;(1<<i)<=a1;i++)if(a1&(1<<i)){
    22         if(f1[a4][i]>a2)a2=f1[a4][i],a3=f2[a4][i]; a4+=(1<<i);
    23     }
    24     q.push((node){f,l,r,a2-s[f-1],a3});
    25 }
    26 int main(){
    27     scanf("%d%d%d%d",&n,&k,&l,&r);
    28     s[0]=0; inc(i,1,n){int a; scanf("%d",&a); s[i]=s[i-1]+a;}
    29     inc(i,1,n-1)f1[i][0]=max(s[i],s[i+1]),f2[i][0]=s[i]>s[i+1]?i:i+1;
    30     for(int j=1;(1<<j)<=n;j++)inc(i,1,n)if(i+(1<<j)<=n){
    31         f1[i][j]=max(f1[i][j-1],f1[i+(1<<(j-1))][j-1]); 
    32         f2[i][j]=s[f2[i][j-1]]>s[f2[i+(1<<(j-1))][j-1]]?f2[i][j-1]:f2[i+(1<<(j-1))][j-1];
    33     }
    34     inc(i,1,n)add(i,i+l-1,min(i+r-1,n)); long long ans=0;
    35     inc(i,1,k){
    36         node now=q.top(); q.pop(); ans=ans+(long long)now.a1; add(now.f,now.l,now.a2-1); add(now.f,now.a2+1,now.r);
    37     }
    38     printf("%lld",ans);
    39     return 0;
    40 }

    20160325

  • 相关阅读:
    讨论一下,乌云漏洞库的学习方法
    a
    asss
    密码重置
    SQL注入2
    起名字真难
    Header
    SQL注入1
    伪装者
    ofbiz 代码日记
  • 原文地址:https://www.cnblogs.com/YuanZiming/p/5656840.html
Copyright © 2011-2022 走看看