我竟然又在写主席树

现在可是九月啦,我却还在写这种noip不可能考的算法

我觉得我真的要凉

题意很明确,就是给你一个序列,让从中选择\(k\)段连续的序列,长度必须大于等于\(L\)小于等于\(R\),让这\(k\)段的和最大

本来认为这是一个非常精妙的\(RMQ\)问题,但是经过一番思考之后发现不会

智商不够,数据结构来凑

看到一个区间的和,我们很自然的想到前缀和,之后我们先枚举每一个数\(x\)作为区间的结尾,之后从\([x-R,x-L]\)中选出最小值来,这样就得到了以每个数作为结尾的符合长度限制的区间最大值,之后我们用一个堆来维护

之后每次取出堆顶位置,统计答案,显然这个我们只考虑了这个位置作为结尾的最大值,没有考虑剩下的可能也会被计入答案的值,所以我们用主席树来找到下一个次小的前缀和,再放到堆里维护

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#define re register
#define maxn 500005
#define max(a,b) ((a)>(b)?(a):(b))
#define mp std::make_pair
typedef std::pair<int,int> pii;
std::priority_queue<pii,std::vector<pii>,std::less<pii> > q;
int pre[maxn],a[maxn],b[maxn],to[maxn],rt[maxn],num[maxn],M[maxn];
int L,R,K,n,tot,cnt;
int ls[maxn*25],rs[maxn*25],d[maxn*25];
int build(int x,int y)
{
int root=++cnt;
if(x==y) return root;
int mid=x+y>>1;
ls[root]=build(x,mid);
rs[root]=build(mid+1,y);
return root;
}
int change(int pre,int x,int y,int pos)
{
int root=++cnt;
d[root]=d[pre]+1;
if(x==y) return root;
ls[root]=ls[pre],rs[root]=rs[pre];
int mid=x+y>>1;
if(pos<=mid) ls[root]=change(ls[pre],x,mid,pos);
else rs[root]=change(rs[pre],mid+1,y,pos);
return root;
}
int query(int p1,int p2,int x,int y,int k)
{
if(x==y) return b[x];
int now=d[ls[p1]]-d[ls[p2]];
int mid=x+y>>1;
if(k>now) return query(rs[p1],rs[p2],mid+1,y,k-now);
return query(ls[p1],ls[p2],x,mid,k);
}
inline int read()
{
char c=getchar();
int x=0,r=1;
while(c<'0'||c>'9')
{
if(c=='-') r=-1;
c=getchar();
}
while(c>='0'&&c<='9')
x=(x<<3)+(x<<1)+c-48,c=getchar();
return x*r;
}
inline int Find(int x)
{
int l=1,r=tot;
while(l<=r)
{
int mid=l+r>>1;
if(b[mid]==x) return mid;
else
{
if(b[mid]>x) r=mid-1;
else l=mid+1;
}
}
}
inline int _to(int x)
{
if(x<0) return 500002;
return x;
}
int main()
{
n=read(),K=read();
L=read(),R=read();
for(re int i=1;i<=n;i++)
a[i]=read();
for(re int i=1;i<=n;i++)
pre[i]=pre[i-1]+a[i],b[i]=pre[i];
b[n+1]=0;
std::sort(b+1,b+n+2);
tot=std::unique(b+1,b+2+n)-b-1;
for(re int i=0;i<=n;i++)
to[i]=Find(pre[i]);
rt[500002]=build(1,tot);
rt[0]=change(rt[500002],1,tot,to[0]);
for(re int i=1;i<=n;i++)
rt[i]=change(rt[i-1],1,tot,to[i]);
int t;
for(re int i=L;i<=n;i++)
t=pre[i]-query(rt[i-L],rt[_to(i-R-1)],1,tot,num[i]+1),num[i]++,q.push(mp(t,i));
M[L]=1;
for(re int i=L+1;i<=R;i++)
M[i]=M[i-1]+1;
for(re int i=R+1;i<=n;i++)
M[i]=R-L+1;
long long ans=0;
while(K--)
{
int k=q.top().second;
ans+=q.top().first;
q.pop();
if(num[k]<M[k]) num[k]++,q.push(mp(pre[k]-query(rt[k-L],rt[_to(k-R-1)],1,tot,num[k]),k));
}
std::cout<<ans;
return 0;
}

时间复杂度\(O(nlogn+klogn)\),好像还要比\(ST\)表快一些

【[NOI2010]超级钢琴】的更多相关文章

  1. BZOJ 2006: [NOI2010]超级钢琴

    2006: [NOI2010]超级钢琴 Time Limit: 20 Sec  Memory Limit: 552 MBSubmit: 2613  Solved: 1297[Submit][Statu ...

  2. Bzoj 2006: [NOI2010]超级钢琴 堆,ST表

    2006: [NOI2010]超级钢琴 Time Limit: 20 Sec  Memory Limit: 552 MBSubmit: 2222  Solved: 1082[Submit][Statu ...

  3. NOI2010超级钢琴 2

    2006: [NOI2010]超级钢琴 Time Limit: 20 Sec  Memory Limit: 552 MBSubmit: 1296  Solved: 606[Submit][Status ...

  4. BZOJ 2006: [NOI2010]超级钢琴( RMQ + 堆 )

    取最大的K个, 用堆和RMQ来加速... ----------------------------------------------------------------- #include<c ...

  5. BZOJ_2006_[NOI2010]超级钢琴_贪心+堆+ST表

    BZOJ_2006_[NOI2010]超级钢琴_贪心+堆+ST表 Description 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的 音乐 ...

  6. bzoj2006 [NOI2010]超级钢琴 (及其拓展)

    bzoj2006 [NOI2010]超级钢琴 给定一个序列,求长度在 \([L,\ R]\) 之间的区间和的前 \(k\) 大之和 \(n\leq5\times10^5,\ k\leq2\times1 ...

  7. P2048 [NOI2010]超级钢琴(RMQ+堆+贪心)

    P2048 [NOI2010]超级钢琴 区间和--->前缀和做差 多次查询区间和最大--->前缀和RMQ 每次取出最大的区间和--->堆 于是我们设个3元组$(o,l,r)$,表示左 ...

  8. 洛谷 P2048 [NOI2010]超级钢琴 解题报告

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

  9. bzoj千题计划162:bzoj2006: [NOI2010]超级钢琴

    http://www.lydsy.com/JudgeOnline/problem.php?id=2006 输出最大的k个 sum[r]-sum[l-1] (L<=r-l+1<=R) 之和 ...

  10. 【BZOJ 2006】2006: [NOI2010]超级钢琴(RMQ+优先队列)

    2006: [NOI2010]超级钢琴 Time Limit: 20 Sec  Memory Limit: 552 MBSubmit: 2792  Solved: 1388 Description 小 ...

随机推荐

  1. ES6学习笔记(一)-变量的解构赋值

    变量的解构赋值种类 解构(Destructuring):ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值. 只有当一个数组成员严格等于(===)undefined,包括空“ ” ,默认值 ...

  2. 13 Reasons Why You Should Pay Attention to Mobile Web Performance

    Mobile is no longer on the sidelines. If you’re not already thinking mobile first, you should at lea ...

  3. Liunx一些命令

    1.设置管理员的密码:sudo passwd root2.获取管理员权限su root3.查看IP地址sudo ifconfig -a4.创建一个文件sudo touch test.txt5.创建一个 ...

  4. 用CSS3/JS绘制自己想要的按钮

    我认为按钮的绘制分以下三个步骤 第一步,绘制按钮的轮廓 选择合适的html标签,设置轮廓的CSS /* html代码 */ <a href="#" class="b ...

  5. 通过vertical-align属性实现“竖向居中”显示

    自学编程大概有大半年的时间了,从15年7月开始学习使用人数最多的JAVA,到后来喜欢上了前端,但由于之间在建筑设计院的工作加班颇为频繁,每天刨去工作,基本没有多少自己个人的时间,只能每天6,7点起床, ...

  6. 爬虫必备—BeautifulSoup

    BeautifulSoup是一个模块,该模块用于接收一个HTML或XML字符串,然后将其进行格式化,之后便可以使用他提供的方法进行快速查找指定元素,从而使得在HTML或XML中查找指定元素变得简单. ...

  7. 01Jenkins环境准备

    01.硬件环境 Linux 64位(windows环境类似) 02.安装JDK a) 标题链接到Oracle官网下载jdk-8u144-linux-x64.rpm b) 将jdk拷贝到Linux的/t ...

  8. HTTP(S)网络框架的设计

    0.麻烦 操作系统提供的网络接口都会令人不爽,要么太接近底层而使用不便,要么层次过高又不提供底层点的接口供设置参数.但是我们不能期望系统API做得很高级,因为没有绝对合适的网络库,必须定制化从而达到适 ...

  9. 一些 Mysql 维护命令

    ----------------------------------------------------------------------------使用mysql客户端程序------------ ...

  10. [转]Linux芯片级移植与底层驱动(基于3.7.4内核)

      1.   SoC Linux底层驱动的组成和现状 为了让Linux在一个全新的ARM SoC上运行,需要提供大量的底层支撑,如定时器节拍.中断控制器.SMP启动.CPU hotplug以及底层的G ...