zoukankan      html  css  js  c++  java
  • 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('
    ')
    #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
    ",ans);
       return 0;
    }
    
    
  • 相关阅读:
    修复ecshop商品重量BUG小数位增至五位
    ECSHOP 支付宝发货确认接口,记录支付宝返回的交易号
    php数字补零的两种方法
    PHP获取当前时间的毫秒数(yyyyMMddHHmmssSSS)
    ajax 设置Access-Control-Allow-Origin实现跨域访问
    MySQL Master High Available 源码篇
    MHA 报错:There is no alive slave. We can't do failover
    cdid
    mha error
    mysql relay log参数汇总
  • 原文地址:https://www.cnblogs.com/captain1/p/10191998.html
Copyright © 2011-2022 走看看