我竟然又在写主席树

现在可是九月啦,我却还在写这种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. 【原】jQuery easyUI 快速搭建前端框架

    jQueryEasyUI jQuery EasyUI是一组基于jQuery的UI插件集合体,而jQuery EasyUI的目标就是帮助web开发者更轻松的打造出功能丰富并且美观的UI界面.开发者不需要 ...

  2. unity assetStore 常用插件

    常用插件 20180723============= 教程类 =============<Mecanim Example Scenes > 官方示例场景<Surivial Shoot ...

  3. [javaSE] GUI(打开文件对话框)

    使用FileDialog可以打开文件对话框,根据模式不同,可以分为打开文件和保存文件对话框 获取FileDialog对象,new出来,参数:所属Frame对象,String的标题,FileDialog ...

  4. mysql随机查询符合条件的几条记录

    随机查询,方法可以有很多种.比如,查询出所有记录,然后随机从列表中取n条记录.使用程序便可实现.可是程序实现必须查询出所有符合条件的记录(至少是所有符合条件的记录id),然后再随机取出n个id,查询数 ...

  5. groovy集合

    groovy集合可以直接在语言中使用,因为它默认已经导入包了. 不需要初始化对象,也不需要专门的类. 集合是groovy语言本地成员.Groovy语法提供了本地列表和相应的映射. 每个Groovy集合 ...

  6. [LeetCode]Letter Combinations of a Phone Number题解

    Letter Combinations of a Phone Number: Given a digit string, return all possible letter combinations ...

  7. BZOJ1149 [CTSC2007]风玲

    Description Input Output 输出仅包含一个整数.表示最少需要多少次交换能使风铃满足Ike的条件.如果不可能满足,输出-1. Sample Input 6 2 3 -1 4 5 6 ...

  8. Spring与Web整合

    一 概述 1.整合目的 将所有对象的创建与管理任务交给Spring容器,降低程序的耦合度. 2.整合途径 将Spring容器注入到Web容器中. 3.具体实现 使用ServletContextList ...

  9. 使用laravel框架与phantomjs实现截屏功能

    在网上看到的关于phantomjs实现截屏功能很多都是与node结合在一起使用,并需要输入命令才能执行.因此我想要实现输入网址即可截屏并输出图片的功能.示例:http://120.77.171.182 ...

  10. Django—Form两种解决表单数据无法动态刷新的方法

    一.无法动态更新数据的实例 1. 如下,数据库中创建了班级表和教师表,两张表的对应关系为“多对多” from django.db import models class Classes(models. ...