https://www.luogu.org/problemnew/show/P2048

http://www.lydsy.com/JudgeOnline/problem.php?id=2006

首先计算出数列的前缀和数组a[0]..a[n],那么问题转化为:从[0,n]中选取任意两个数(i,j)使得i<j,计算a[j]-a[i];对于所有合法的数对(i,j),求第k大的a[j]-a[i]的值。

考虑枚举i,对于每一个i要得到第k大的a[j]-a[i],则需要从[i+1,n]中选取j使得a[j]是a[i+1]到a[n]中第k大的。

用一个优先队列维护一下,然后问题就只剩区间k大了。可以用静态主席树搞一下。

但是你会发现T到飞起...常数太大了2333333

本来动态开点偷懒都不行了

 #pragma GCC optimize("Ofast")
#pragma GCC optimize("inline","fast-math","unroll-loops","no-stack-protector")
#pragma GCC diagnostic error "-fwhole-program"
#pragma GCC diagnostic error "-fcse-skip-blocks"
#pragma GCC diagnostic error "-funsafe-loop-optimizations"
#pragma GCC diagnostic error "-std=c++14"
#include<cstdio>
#include<algorithm>
#include<queue>
#include<tr1/unordered_map>
#define mid ((l+r)>>1)
using namespace std;
typedef long long LL;
typedef pair<LL,int> P;
tr1::unordered_map<LL,int> ma;
LL tmp[],ma2[];
int mem,lc[],rc[],dat[],root[];
LL ll,rr,totn;
LL L;int x;
//root[i]表示[i+L,i+R]区间的线段树,也就是选i+1号为左端点时右端点可取范围
void addx(LL l,LL r,int& num)
{
int t=num;num=++mem;//if(mem>=40000000){puts("test");exit(0);}
lc[num]=lc[t];rc[num]=rc[t];dat[num]=dat[t];
if(l==r) {dat[num]+=x;return;}
if(L<=mid) addx(l,mid,lc[num]);
else addx(mid+,r,rc[num]);
dat[num]=dat[lc[num]]+dat[rc[num]];
}
LL getx(LL l,LL r,int num)//第x大
{
if(l==r) return l;
if(dat[rc[num]]>=x) return getx(mid+,r,rc[num]);
else return x-=dat[rc[num]],getx(l,mid,lc[num]);
}
int n,k,lx,rx;LL ans;
LL a[];int nownum[];
priority_queue<P> q;
//P(当前和,i)(当前和等于[i+L,i+R]的第nownum[i]大-a[i])
//void out(LL l,LL r,LL num)
//{
// if(l==r) {for(LL i=1;i<=dat[num];i++) printf("%lld ",l);return;}
// out(l,mid,lc[num]);out(mid+1,r,rc[num]);
//}
//void out()
//{
// queue<P> qq;P t;
// while(!q.empty()) {t=q.top();q.pop();printf("%lld %lld\n",t.first,t.second);qq.push(t);}
// while(!qq.empty()) {t=qq.front();qq.pop();q.push(t);}
//}
int main()
{
int l=,r=-,i;P t;
scanf("%d%d%d%d",&n,&k,&lx,&rx);
for(i=;i<=n;i++) scanf("%lld",&a[i]),a[i]+=a[i-],tmp[++tmp[]]=a[i];
sort(tmp+,tmp+tmp[]+);totn=unique(tmp+,tmp+tmp[]+)-tmp-;
for(i=;i<=totn;i++) ma[tmp[i]]=i,ma2[i]=tmp[i];
for(i=;i<=n;i++) a[i]=ma[a[i]];
ll=;rr=totn;
while(r<n&&r<rx) r++,L=a[r],x=,addx(ll,rr,root[]);
while(l<=n&&l<lx) L=a[l],x=-,addx(ll,rr,root[]),l++;
if(l<=r)
{
x=nownum[]=;
q.push(P(ma2[getx(ll,rr,root[])]-ma2[a[]],));
}
for(i=;i<n;i++)
{
root[i]=root[i-];
while(r<n&&r<i+rx) r++,L=a[r],x=,addx(ll,rr,root[i]);
while(l<=n&&l<i+lx) L=a[l],x=-,addx(ll,rr,root[i]),l++;
if(l<=r)
{
x=nownum[i]=;
q.push(P(ma2[getx(ll,rr,root[i])]-ma2[a[i]],i));
}
}
//out();
//printf("\n%lld",mem);
//return 0; for(i=;i<=k;i++)
{
t=q.top();q.pop();
//printf("a%lld\n",t.first);
ans+=t.first;
++nownum[t.second];
//l=min(n+1,t.second+lx);r=min(n,t.second+rx);
//if(r-l+1<nownum[t.second]) continue;
if(dat[root[t.second]]<nownum[t.second]) continue;
x=nownum[t.second];
q.push(P(ma2[getx(ll,rr,root[t.second])]-ma2[a[t.second]],t.second));
}
printf("%lld",ans); //for(i=0;i<n;i++) {out(ll,rr,root[i]);puts("");}
return ;
}

错误记录:90行写成dat[t.second];动态开点(没有离散化)时误以为值域只有-1000到1000(但事实上值域是前缀和的值域,-5e8到5e8)

开了奇怪的Ofast后A掉了....

其实有更优越的做法,就是维护优先队列时,每次搞完[l,r]区间最大值(在k位置)后,就把它拆成[l,k-1]和[r+1,k](还有这两个区间内分别的最小值)分别放回去,这样恰好去掉了之前的最大值,又不破坏次大值、第三大值、....。这样只需要ST表预处理一下然后RMQ就行了,好写&常数小


这里有一个一模一样的题,并过来

洛谷 P2048 [NOI2010]超级钢琴 || Fantasy的更多相关文章

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

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

  2. [洛谷P2048] [NOI2010] 超级钢琴

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

  3. 洛谷P2048 [NOI2010]超级钢琴 题解

    2019/11/14 更新日志: 近期发现这篇题解有点烂,更新一下,删繁就简,详细重点.代码多加了注释.就酱紫啦! 正解步骤 我们需要先算美妙度的前缀和,并初始化RMQ. 循环 \(i\) 从 \(1 ...

  4. 洛谷 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]$是一个定值,所以我们只要在 ...

  5. 洛谷P0248 [NOI2010] 超级钢琴 [RMQ,贪心]

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

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

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

  7. 【题解】P2048 [NOI2010]超级钢琴

    [题解][P2048 NOI2010]超级钢琴 一道非常套路的题目.是堆的套路题. 考虑前缀和,我们要是确定了左端点,就只需要在右端区间查询最大的那个加进来就好了.\(sum_j-sum_{i-1}​ ...

  8. LGOJ P2048 [NOI2010]超级钢琴

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

  9. 洛谷$P$2048 超级钢琴 $[NOI2010]$ $rmq$/主席树

    正解:$rmq$/主席树 解题报告: 传送门! 好像看过这题挺多次辣,,,$QwQ$ 之前$NOIp$的时候$cjk$学长讲课讲了这题(虽然那时候的$gql$太菜辣并麻油落实这道_(:з」∠)_,然后 ...

随机推荐

  1. 【Nginx】如何使用http配置

    处理http配置项可以分为下面4个步骤: 1)创建数据结构用于存储配置项对应的参数 2)设定配置项在nginx.conf中出现时的限制条件与回调方法 3)实现第2步中的回调方法,或者使用Nginx框架 ...

  2. Office Adobe Acrobat把PDF转换为Word时候提示不支持的Type2字体怎么办

    如下图所示,在使用Adobe Acrobat Pro9将PDF转换为Word的时候出现下面的错误   很简单,不要用Adobe Acrobat Pro9了,用Adobe Acrobat Pro X,还 ...

  3. SpringMVC+Hibernate+Junit4+json基本框架近乎0配置

    公司是做APP开发的,须要后台来提供接口,于是乎,这个任务就交给我,经过重复的尝试,学习和參考别人的demo,最终搭出自己还算惬意的框架.SpringMVC+Sping3+Hibernate4+Jun ...

  4. Python练习题2

    如果真的想学精,学什么都不是好学的,如果真的想把Python学的出神入化,几乎自己想做什么都可以,就要下定恒心,坚持下去. 接下来继续更新Python练习题2,通过更新前一部的练习题让自己也学到了不少 ...

  5. 【转载】How browsers work--Behind the scenes of modern web browsers (前端必读)

    浏览器可以被认为是使用最广泛的软件,本文将介绍浏览器的工 作原理,我们将看到,从你在地址栏输入google.com到你看到google主页过程中都发生了什么. 将讨论的浏览器 今天,有五种主流浏览器- ...

  6. android &lt;application&gt; 开发文档翻译

    由于本人英文能力实在有限,不足之初敬请谅解 本博客仅仅要没有注明"转",那么均为原创.转贴请注明本博客链接链接 <application>语法:    <appl ...

  7. 实践部署与使用apache kafka框架技术博文资料汇总

    前一篇Kafka框架设计来自英文原文(Kafka Architecture Design)的翻译及整理文章,非常有借鉴性,本文是从一个企业使用Kafka框架的角度来记录及整理的Kafka框架的技术资料 ...

  8. Android进阶图片处理之三级缓存方案

    图片的三级缓存 一.概述 一開始在学习Android的时候.处理图片的时候,每次获取图片都是直接从网络上面载入图片. 可是在开发项目的过程中,每次点击进入app里面,图片都要慢慢的再一次从网络上面载入 ...

  9. 安全相关的head头

    与安全相关的head头包括 参考网站:https://developer.mozilla.org/en-US/docs/Web/HTTP Content-Security-Policy(CSP):禁止 ...

  10. Expression Blend实例中文教程系列

    Expression Blend实例中文教程系列 本系列文章均转载:银光中国 时间:2010-04-09 09:20责任编辑:银光中国网 点击:次 Expression Blend实例中文教程系列由C ...