NOI2010 超级钢琴

传送门

题目大意:给定一个长为n的序列。求序列中所有长在\(L~R\)内的价值前K大的连续子序列价值之和。每个子序列的价值是其所有元素之和。

首先我们肯定是要用前缀和相减的方式来计算的。每次取最大的区间,之后只要我们把这个区间删除,继续计算就可以了。

我们有一个很朴素的想法就是枚举左端点,然后用st表求出相对应的最大值的位置和最大值。我们可以先把这些答案都放在一个堆中,取最大,之后删除区间。

怎么删除呢?考虑到删除这个区间,相当于我们能选取的答案区间少了这个节点。那我们只要把这个节点从堆中删除,存入其左右的两个节点即可。注意如果重复了就不要加入。

实现的方法就是开一个结构体维护一下,使用构造函数维护一下就好。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#define rep(i,a,n) for(register int i = a;i <= n;i++)
#define per(i,n,a) for(register int i = n;i >= a;i--)
#define enter putchar('\n')
#define pr pair<int,int>
#define mp make_pair
#define fi first
#define sc second
using namespace std;
typedef long long ll;
const int M = 500005;
const int N = 10000005;
 
int read()
{
   int ans = 0,op = 1;char ch = getchar();
   while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
   while(ch >='0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();
   return ans * op;
}

int n,k,L,R,lg[M],a[M],st[20][M],sum[M];
ll ans;

void init()
{
   lg[0] = -1;
   rep(i,1,n) st[0][i] = i,lg[i] = lg[i>>1] + 1;
   rep(j,1,lg[n])
   {
      rep(i,1,n)
      {
	 if(i + (1 << j) - 1 > n) break;
	 int x = st[j-1][i],y = st[j-1][i+(1<<(j-1))];
	 if(sum[x] > sum[y]) st[j][i] = x;
	 else st[j][i] = y;
      }
   }
}

int query(int kl,int kr)
{
   int k = lg[kr - kl + 1],x = st[k][kl],y = st[k][kr - (1<<k) + 1];
   if(sum[x] > sum[y]) return x;
   else return y;
}

struct node
{
   int p,l,r,pos;
   node(){}
   node(int kp,int kl,int kr)
   {
      p = kp,l = kl,r = kr;
      pos = query(kl,kr);
   }
   bool operator < (const node &g) const
   {
      return sum[pos] - sum[p-1] < sum[g.pos] - sum[g.p-1];
   }
}b[M];

priority_queue <node> q;

int main()
{
   n = read(),k = read(),L = read(),R = read();
   rep(i,1,n) a[i] = read(),sum[i] = sum[i-1] + a[i];
   init();
   rep(i,1,n) if(i+L-1 <= n)q.push(node(i,i+L-1,min(i+R-1,n)));
   while(k--)
   {
      node c = q.top();q.pop();
      ans += sum[c.pos] - sum[c.p-1];
      if(c.pos != c.l) q.push(node(c.p,c.l,c.pos-1));
      if(c.pos != c.r) q.push(node(c.p,c.pos+1,c.r));
   }
   printf("%lld\n",ans);
   return 0;
}

posted @ 2018-12-28 17:53  CaptainLi  阅读(174)  评论(0编辑  收藏  举报