zoukankan      html  css  js  c++  java
  • 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,表示按编号从小到大每个音符的美妙度。
    Output
    只有一个整数,表示乐曲美妙度的最大值。
    Sample Input
    4 3 2 3

    3

    2

    -6

    8

    Sample Output
    11

    【样例说明】
    共有5种不同的超级和弦:

    音符1 ~ 2,美妙度为3 + 2 = 5
    音符2 ~ 3,美妙度为2 + (-6) = -4
    音符3 ~ 4,美妙度为(-6) + 8 = 2
    音符1 ~ 3,美妙度为3 + 2 + (-6) = -1
    音符2 ~ 4,美妙度为2 + (-6) + 8 = 4
    最优方案为:乐曲由和弦1,和弦3,和弦5组成,美妙度为5 + 2 + 4 = 11。

    给jzp跪了,想不到竟然可以这样

    首先原来有一道这样的题,就是有a,b两个有序数组,c[i,j]表示a[i]+b[i],输出前k小

    这个大家都知道,用堆维护每一行的当前最小值(就是最前面的数啦),每次取一个元素,就把这一行的列+1,然后再加进堆

    这个我一开始想法也差不多,先处理一个前缀和,区间[l,r]的和就变成了s[r]-s[l-1]所以也变成和上面那个差不多的东西,但是无序

    所以我们还要支持查找区间k大,这样复杂度略高

    于是jzp就给出了一个更好的,我们用三元组(i,l,r)表示左端点为i,右端点再[l,r]的最大值,一开始显然有n个元素

    然后当我们取出元素(i,l,r)时,我们要更新,我们把它拆成两份,假设最大值在k处取得,我们就把(i,l,k-1)和(i,k+1,r)加入堆中

    这样复杂度是O((n+k)log(n+k))就毫无压力了

      1 const
      2     maxn=500500;
      3 type
      4     node=record
      5         i,l,r,max:longint;
      6     end;
      7 var
      8     q:array[0..maxn*2]of node;
      9     s:array[0..maxn]of int64;
     10     f:array[0..maxn,0..20]of longint;
     11     n,k,l,r,tot:longint;
     12     ans:int64;
     13  
     14 procedure rmq;
     15 var
     16     i,k:longint;
     17 begin
     18     for i:=1 to n do f[i,0]:=i;
     19     k:=0;
     20     while 1<<k<<1<=n do
     21         begin
     22             for i:=1 to n-1<<k<<1+1 do
     23                 if s[f[i,k]]>s[f[i+1<<k,k]] then f[i,k+1]:=f[i,k]
     24                 else f[i,k+1]:=f[i+1<<k,k];
     25             inc(k);
     26         end;
     27 end;
     28  
     29 function max(l,r:longint):longint;
     30 var
     31     k:longint;
     32 begin
     33     k:=0;
     34     while r-l+1>1<<k<<1 do inc(k);
     35     if s[f[r-1<<k+1,k]]>s[f[l,k]] then exit(f[r-1<<k+1,k]);
     36     exit(f[l,k]);
     37 end;
     38  
     39 procedure swap(var x,y:node);
     40 var
     41     t:node;
     42 begin
     43     t:=x;x:=y;y:=t;
     44 end;
     45  
     46 procedure up(x:longint);
     47 var
     48     i:longint;
     49 begin
     50     while x>1 do
     51         begin
     52             i:=x>>1;
     53             if s[q[x].max]-s[q[x].i]> s[q[i].max]-s[q[i].i] then
     54                 begin
     55                     swap(q[i],q[x]);
     56                     x:=i;
     57                 end
     58             else exit;
     59         end;
     60 end;
     61  
     62 procedure down(x:longint);
     63 var
     64     i:longint;
     65 begin
     66     i:=x<<1;
     67     while i<=tot do
     68         begin
     69             if (i<tot) and (s[q[i+1].max]-s[q[i+1].i]>s[q[i].max]-s[q[i].i]) then inc(i);
     70             if s[q[i].max]-s[q[i].i]>s[q[x].max]-s[q[x].i] then
     71                 begin
     72                     swap(q[i],q[x]);
     73                     x:=i;i:=x<<1;
     74                 end
     75             else exit;
     76         end;
     77 end;
     78  
     79 procedure insert(i,l,r:longint);
     80 begin
     81     if r>n then r:=n;
     82     if l>r then exit;
     83     inc(tot);
     84     q[tot].i:=i;q[tot].l:=l;q[tot].r:=r;
     85     q[tot].max:=max(l,r);
     86     up(tot);
     87 end;
     88  
     89 procedure delete;
     90 begin
     91     swap(q[1],q[tot]);
     92     dec(tot);
     93     down(1);
     94 end;
     95  
     96 procedure main;
     97 var
     98     i:longint;
     99 begin
    100     read(n,k,l,r);
    101     for i:=1 to n do read(s[i]);
    102     for i:=2 to n do inc(s[i],s[i-1]);
    103     rmq;
    104     for i:=0 to n-1 do insert(i,i+l,i+r);
    105     for i:=1 to k do
    106         begin
    107             inc(ans,s[q[1].max]-s[q[1].i]);
    108             insert(q[1].i,q[1].l,q[1].max-1);insert(q[1].i,q[1].max+1,q[1].r);
    109             delete;
    110         end;
    111     writeln(ans);
    112 end;
    113  
    114 begin
    115     main;
    116 end.
    View Code
  • 相关阅读:
    洛谷P3233 世界树
    线性基
    CF321E Ciel and Gondolas
    洛谷P2619 Tree I
    重温一下基本数据类型以及自动提升数据类型的问题
    不可理喻的JSTL标签库
    理解RESTful架构(转)
    Node.js的优点和缺点(转载)
    自制双色球随机号码
    编程, 细心永远都不嫌多(记录java连接数据库的一个错误)
  • 原文地址:https://www.cnblogs.com/Randolph87/p/3805767.html
Copyright © 2011-2022 走看看