BZOJ2006: [NOI2010]超级钢琴

Posted 嘒彼小星

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ2006: [NOI2010]超级钢琴相关的知识,希望对你有一定的参考价值。

2006: [NOI2010]超级钢琴

Time Limit: 20 Sec  Memory Limit: 552 MB
Submit: 3234  Solved: 1594
[Submit][Status][Discuss]

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,表示按编号从小到大每个音符的美妙度。
N<=500,000
k<=500,000
-1000<=Ai<=1000,1<=L<=R<=N且保证一定存在满足条件的乐曲

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。

HINT


Source

 

【题解】

初始时,对于每一个右端点,他所选的最优左端点很容易求出:前缀和+st表

贪心选区间和最大的(堆实现)。选了某个右端点i,对应左端点pos后,

只要i不被选,以i为右端点的区间的左端点不是pos的区间就不可能被选

pos被选了之后

我们不难发现

右端点i的最优左端点在i - r + 1, pos - 1 和 pos + 1, i - l + 1里面

 

取两个左端点最优值压入堆中嘛?当然不是,两个左端点都应加入堆中。

两个端点一个能构成最大,另一个可能构成次大。

因long long和st表的ij弄反被卡

 

技术分享
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <queue>
  6 #include <vector>
  7 #define max(a, b) ((a) > (b) ? (a) : (b))
  8 #define min(a, b) ((a) < (b) ? (a) : (b))
  9 
 10 inline void read(long long &x)
 11 {
 12     x = 0;char ch = getchar(), c = ch;
 13     while(ch < 0 || ch > 9)c = ch, ch = getchar();
 14     while(ch <= 9 && ch >= 0)x = x * 10 + ch - 0, ch = getchar();
 15     if(c == -)x = -x;
 16 }
 17 
 18 const long long MAXN = 500000 + 10;
 19 const long long MAXK = 500000 + 10;
 20 
 21 long long n,k,l,r,num[MAXN],st[20][MAXN],rank[20][MAXN],M,pow2[30],ans;
 22 
 23 struct Node
 24 {
 25     long long value, l, r, rank, i;
 26     Node(long long _value, long long _l, long long _r, long long _rank, long long _i){value = _value, l = _l, r = _r,rank = _rank;i = _i;}    
 27     Node(){}
 28 };
 29 
 30 struct cmp
 31 {
 32     bool operator()(Node a, Node b)    
 33     {
 34         return a.value < b.value;
 35     }
 36 };
 37 
 38 std::priority_queue<Node, std::vector<Node>, cmp> q;
 39 
 40 void yuchuli()
 41 {
 42     while(pow2[M] <= n)++ M;
 43     --M;
 44     for(register long long i = 1;i <= M;++ i)
 45         for(register long long j = 0;j <= n;++ j)
 46         {
 47             if(j + pow2[i] - 1 > n)continue;
 48             if(st[i - 1][j] < st[i - 1][j + pow2[i - 1]])
 49             {
 50                 st[i][j] = st[i - 1][j];
 51                 rank[i][j] = rank[i - 1][j];
 52             }
 53             else
 54             {
 55                 st[i][j] = st[i - 1][j + pow2[i - 1]];
 56                 rank[i][j] = rank[i - 1][j + pow2[i - 1]];
 57             }
 58         }
 59 }
 60 
 61 long long find(long long l, long long r)
 62 {
 63     if(l > r)
 64     {
 65         long long tmp = l;
 66         l = r;
 67         r = tmp;
 68     }
 69     long long m = 0;
 70     while(pow2[m] <= (r - l + 1))++ m;
 71     -- m;
 72     if(st[m][l] < st[m][r - pow2[m] + 1])
 73         return rank[m][l];
 74     else
 75         return rank[m][r - pow2[m] + 1];
 76 }
 77 
 78 int main()
 79 {
 80     read(n);read(k);read(l);read(r);
 81     pow2[0] = 1;
 82     for(register long long i = 1;i <= 25;++ i)pow2[i] = (pow2[i - 1] << 1);
 83     for(register long long i = 1;i <= n;++ i)
 84     {
 85         read(num[i]);
 86         num[i] += num[i - 1];
 87         st[0][i] = num[i];
 88         rank[0][i] = i;
 89     }
 90     yuchuli();
 91     for(register long long i = l;i <= n;++ i)
 92     {
 93         long long k = find(max(0, i - r), max(i - l, 0));
 94         q.push(Node(num[i] - num[k], max(0, i - r), max(i - l, 0), k, i));
 95     }
 96     long long now = 0;
 97     register Node tmp;
 98     register long long pos;
 99     for(;now < k;++ now)
100     {
101         tmp = q.top(), q.pop();
102         long long l = tmp.l, r = tmp.r;
103         ans += tmp.value; 
104         if(tmp.l <= tmp.rank - 1 && tmp.l >= 0)
105         {
106             pos = find(max(0, tmp.l), max(tmp.rank - 1, 0));
107             q.push(Node(num[tmp.i] - num[pos], tmp.l, tmp.rank - 1, pos, tmp.i));
108         }
109         if(tmp.r >= tmp.rank + 1)
110         {
111             pos = find(max(0, tmp.rank + 1), max(tmp.r, 0));
112             q.push(Node(num[tmp.i] - num[pos], tmp.rank +1, tmp.r, pos, tmp.i));
113         }
114     }
115     printf("%lld", ans);
116     return 0;
117 }
BZOJ2006

 

以上是关于BZOJ2006: [NOI2010]超级钢琴的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 2006: [NOI2010]超级钢琴

[BZOJ2006][NOI2010]超级钢琴

bzoj 2006 [NOI2010]超级钢琴 rmq+堆

BZOJ2006[NOI2010]超级钢琴 ST表+堆

[BZOJ2006][NOI2010]超级钢琴(ST表+堆)

[BZOJ2006] [NOI2010]超级钢琴 主席树+贪心+优先队列