2006: [NOI2010]超级钢琴

Time Limit: 20 Sec Memory Limit: 552 MB
Submit: 1778 Solved: 871
[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,表示按编号从小到大每个音符的美妙度。
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。

我们处理出这样一个东西(i,L,R)表示当这个和弦的左端点为i时在上限和下限中的最优值。(也就是右端点在[i+l-1,i+r-1]中)
我们将第一步处理出来的所有最优值扔到一个堆里面,然后每次从堆中选取最大的出来,将ans加上这个数。假设我们在这段区间中选取最优值得位置为where,那么我们就这段区间[L,R]裂解成两段区间[L,where-1]和[where+1,R],再讲这两段区间放到堆里面。
这样其实就是每次选取了一个最优值,然后把那些小于最优值的数放进去。
选取了K次之后就是答案。

我们对于第一步的处理,其实有两种方法:
首先我们都需要处理出前缀和这个东西来,然后就是查询区间最值,查完后再加上i到L的值就好了。对于查区间最值:
①:我们可以用线段树。但是我们的查询次数是(n+k),所以会比较慢。
②:我们可以用ST(一种跟倍增差不多的东西),用ST就可以做到O(1)的查询,会快很多

然后堆就直接STL把,手写比较麻烦
(由于我比较弱,想了一下午才想出怎么做。。。)

线段树+priority_queue

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define inf 210000000LL
const int N=500100;
int n,K,a[N];
long long ans=0;
struct S{int where,maxn;void init(){maxn=-inf;where=0;}
}tr[N*4];
struct heap{int maxn,where,left,llimit,rlimit;};
priority_queue<heap> q;
bool operator < (heap x,heap y){return x.maxn<y.maxn;}
int in()
{int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;
}
#define mid (l+r)/2
#define L k<<1,l,mid
#define R k<<1|1,mid+1,r
void build(int k,int l,int r)
{if(l==r){tr[k].maxn=a[l];tr[k].where=l;return ;}build(L); build(R);tr[k].maxn=max(tr[k<<1].maxn,tr[k<<1|1].maxn);if(tr[k<<1].maxn>tr[k<<1|1].maxn) tr[k].where=tr[k<<1].where;if(tr[k<<1].maxn<=tr[k<<1|1].maxn) tr[k].where=tr[k<<1|1].where;
}
S ask(int k,int l,int r,int x,int y)
{S ans1,ans2;ans1.init();ans2.init();if(x<=l&&y>=r) return tr[k];if(x<=mid) ans1=ask(L,x,y);if(y>mid) ans2=ask(R,x,y);if(ans1.maxn<ans2.maxn){ans1.maxn=ans2.maxn;ans1.where=ans2.where;}return ans1;
}
int main()
{int i,j,l,r,ll,rr;S t;heap ans1;n=in();K=in();l=in();r=in();for(i=1;i<=n;++i) a[i]=in(),a[i]+=a[i-1];build(1,1,n);   for(i=1;i<=n-l+1;++i){ll=i+l-1,rr=min(i+r-1,n);t=ask(1,1,n,ll,rr);q.push((heap){t.maxn-a[i-1],t.where,i,ll,rr});}while(K--){ans1=q.top();q.pop();ans+=(long long)ans1.maxn;if(ans1.where-1>=ans1.llimit){t=ask(1,1,n,ans1.llimit,ans1.where-1);q.push((heap){t.maxn-a[ans1.left-1],t.where,ans1.left,ans1.llimit,ans1.where-1});}if(ans1.where+1<=ans1.rlimit){t=ask(1,1,n,ans1.where+1,ans1.rlimit);q.push((heap){t.maxn-a[ans1.left-1],t.where,ans1.left,ans1.where+1,ans1.rlimit});}}printf("%lld\n",ans);
}

ST+priority_queue

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
using namespace std;
#define inf 210000000LL
const int N=500100;
int n,K,a[N];
long long ans=0;
struct S{int maxn,where;}f[20][N];
struct heap{int maxn,where,left,llimit,rlimit;};
priority_queue<heap> q;
bool operator < (heap x,heap y){return x.maxn<y.maxn;}
int in()
{int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void prepare()
{
    int i,j;
    for(i=1;i<=20;++i)
      for(j=1;j+(1<<i)-1<=n;++j){        f[i][j].maxn=max(f[i-1][j].maxn,f[i-1][j+(1<<i>>1)].maxn);
        if(f[i-1][j].maxn>f[i-1][j+(1<<i>>1)].maxn) f[i][j].where=f[i-1][j].where;
        else f[i][j].where=f[i-1][j+(1<<i>>1)].where;
      }
}
S ask(int x,int y)
{S ans1;int t=(int)(log(y-x+1.0)/log(2.0));ans1.maxn=max(f[t][x].maxn,f[t][y-(1<<t)+1].maxn);if (f[t][x].maxn>f[t][y-(1<<t)+1].maxn) ans1.where=f[t][x].where;else ans1.where=f[t][y-(1<<t)+1].where;return ans1;
}
int main()
{
    int i,j,l,r,ll,rr;
    S t;
    heap ans1;
    n=in();K=in();l=in();r=in();
    for(i=1;i<=n;++i){        a[i]=in();
        a[i]+=a[i-1];
        f[0][i].maxn=a[i];
        f[0][i].where=i;
    }
    prepare();
    for(i=1;i<=n-l+1;++i){        ll=i+l-1,rr=min(i+r-1,n);
        t=ask(ll,rr);
        q.push((heap){t.maxn-a[i-1],t.where,i,ll,rr});
    }
    while(K--){        ans1=q.top();
        q.pop();
        ans+=(long long)ans1.maxn;
        if(ans1.where-1>=ans1.llimit){            t=ask(ans1.llimit,ans1.where-1);
            q.push((heap){t.maxn-a[ans1.left-1],t.where,ans1.left,ans1.llimit,ans1.where-1});
        }
        if(ans1.where+1<=ans1.rlimit){            t=ask(ans1.where+1,ans1.rlimit);
            q.push((heap){t.maxn-a[ans1.left-1],t.where,ans1.left,ans1.where+1,ans1.rlimit});
        }
    }
    printf("%lld\n",ans);
}

【bzoj2006】【NOI2010】【超级钢琴】相关推荐

  1. BZOJ2006 [NOI2010]超级钢琴 【堆 + RMQ】

    2006: [NOI2010]超级钢琴 Time Limit: 20 Sec  Memory Limit: 552 MB Submit: 3446  Solved: 1692 [Submit][Sta ...

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

    2006: [NOI2010]超级钢琴 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 3708  Solved: 1846 [Submit][Sta ...

  3. [NOI2010]超级钢琴 主席树

    [NOI2010]超级钢琴 链接 luogu 思路 和12省联考的异或粽子一样. 堆维护n个左端点,每次取出来再放回去次 代码 #include <bits/stdc++.h> #defi ...

  4. NOI2010超级钢琴

    **NOI2010 超级钢琴** **Description** 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐. 这架超级钢琴可以弹奏出 ...

  5. P2048 [NOI2010] 超级钢琴(ST表 + 优先队列优化)

    P2048 [NOI2010] 超级钢琴 题目 小 Z 是一个小有名气的钢琴家,最近 C 博士送给了小 Z 一架超级钢琴,小 Z 希望能够用这架钢琴创作出世界上最美妙的音乐. 这架超级钢琴可以弹奏出 ...

  6. 贪心(数据结构):COGS 468. [NOI2010]超级钢琴

    ★★★☆   输入文件:piano.in   输出文件:piano.out   简单对比 时间限制:2 s   内存限制:512 MB 超级钢琴 [问题描述] 小Z是一个小有名气的钢琴家,最近C博士送 ...

  7. P2048 [NOI2010]超级钢琴

    传送门 考虑维护前缀和 $sum[i]$ 那么对于每一个位置 $i$ ,左端点为 $i$ 右端点在 $[i+L-1,i+R-1]$ 区间的区间最大值容易维护 维护三元组 $(o,l,r)$ ,表示左端 ...

  8. 洛谷 P2048 [NOI2010]超级钢琴(优先队列,RMQ)

    传送门 我们定义$(p,l,r)=max\{sum[t]-sum[p-1],p+l-1\leq t\leq p+r-1 \}$ 那么因为对每一个$p$来说$sum[p-1]$是一个定值,所以我们只要在 ...

  9. P2048 [NOI2010] 超级钢琴(RMQ 贪心)

    文章目录 题目描述 解析 代码 传送门 题目描述 解析 首先,如果只有一个和弦,那么问题显然简单了 用前缀和结合ST表随便做做即可 然而 这次要求前k大的 怎么办呢? 参照之前有一道序列合并的做法 我 ...

  10. [NOI2010] 超级钢琴

    题目类型:RMQ+堆 传送门:>Here< 题意:给出一个长度为\(N\)的序列\(a\),对于每一个\(i\)作为和弦的起点,长度可以是\(L \rightarrow R\).问所有和弦 ...

最新文章

  1. 完整的目标管理三段俱全
  2. CNN结构:用于检测的CNN结构进化-分离式方法
  3. 51单片机雾化片自动扫频程序_单片机简介
  4. python 消息框但不影响程序执行_还在用print()查找错误?日志消息不香嘛?| 原力计划...
  5. P3275 [SCOI2011]糖果
  6. 体验VMware Converter Client 6.2与Veeam BR 10迁移ESXi 6.0 vm到vCenter 6.7 u3
  7. java juc 包_JUC java并发包
  8. 鸿蒙推送荣耀,华为鸿蒙首批推送机型8款,荣耀“避嫌”,不在首批名单
  9. HTTP缓存原理及相关知识(1)
  10. SQL:postgresql查询某个字段最大值行的其他字段值
  11. 联想裁员:公司不是我的家
  12. apache服务器(修改主页文件、两个不同ip访问不同站点、统一ip不同端口访问不同站点)
  13. 解决vscode导致电脑很卡
  14. P2916 [USACO08NOV]安慰奶牛Cheering up the Cow
  15. 商户接入微信支付方法(扫码支付、刷卡、app)
  16. r语言使用linux命令,技术|如何在 Ubuntu 上安装和使用 R 语言
  17. .net 后端生成海报
  18. Camstar 元数据mdb辅助工具
  19. CityMaker学习教程07 示例代码的使用CSharp
  20. 辉光管电子时钟DIY记录-动态扫描驱动方式

热门文章

  1. 交易策略理想与现实之间的距离之流动性
  2. 基于VoIP视频通话系统构建
  3. 贝加莱 C语言编程,贝加莱可编程计算机控制器PCC系列
  4. Camtasia2022完整的许可证密钥
  5. 转:谨防企业信息化的洋务运动--兼谈互联网时代的管理变革
  6. 关于Unity场景跳转后光线变暗问题
  7. Android png图片彩色转黑白,透明度打印变黑色的解决方法
  8. 4.1-2黄金走势分析,一旦失守关键支撑,黄金白银恐将大跌
  9. 记录我复习和备考教师资格证的过程
  10. 吾爱IC社区2019年度总结