题目大意

给出一个序列和\(L, R\), 求前k大长度在\([L,R]\)之间的连续子序列的和的和.

解题思路

朴素的想法是对于一个左端点\(p\), 它的右区间取值范围是一个连续的区间即\([p+L-1,p+R-1]\). 枚举这些区间的和然后排序一下什么的, 当然可以用前缀和优化.

考虑对于一个左端点和一个右端点的区间组成的三元组, 设它的答案是\(f(p,l,r)\),那么\(f(p,l,r)\)是一个固定的数, 即\(f(p,l,r)=max(sum(p,r)), \text{其中}(r\in [p+L-1,p+R-1])\).

转化为前缀和后, \(sum(p,r)=sum_r-sum_{p-1}\), 由于\(sum_{p-1}\)一定, 其实就是\(sum_r\)最大的\(r\)最优. 于是这样的最优的\(r\)可以用ST表在\(O(1)\)的时间内求出.

实际上对于每一个左端点都有一个类似的三元组, 考虑如何能把最大的前\(k\)个子序列求出.

若此时\(f(p,l,r)\)(设\([l,r]\)中最优的端点是\(w\))最大, 将\(f(p,l,r)\)累加到答案的同时, \([l,r]\)这个右端点区间会分裂成两个区间\([l,w)\)和\((w,r]\)(前提是这样的区间存在).

为什么? \(w\)只是\([l,r]\)中最大的右端点, 实际上次大的, 第三大的..都能作为可能的答案.

根据上面的分析, 解法已经呼然欲出: 我们维护一个大根堆, 每次取出最大的三元组, 累加答案并分裂区间加入堆. 由于一共只会分裂\(k\)次的区间, 所以堆中的元素不超过\(n+k\)个.

加上预处理, 时间复杂度\(O(n\log{n}+k\log{(n+k)})\).

后记

自己的数据结构真的好差.. 某些大佬(pzr等人)用主席树也能过, 我又不会....

PS:洛谷上的数据范围比标程要大一些

#include <queue>
#include <cstdio>
#include <cstring>
#define W 17
#define N 100010
#define ll long long
#define fo(i, a, b) for(int i = (a); i <= (b); ++i)
#define fd(i, a, b) for(int i = (a); i >= (b); --i)
using namespace std;
inline int min(int a, int b){return a < b ? a : b;}
inline int read()
{
int x = 0; char ch = getchar(); bool ne = 0;
while(ch < '0' || ch > '9') ne |= (ch == '-'), ch = getchar();
while(ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
return ne ? -x : x;
}
int n, k, L, R, lg[N], p2[W + 3] = {1}, sum[N];
ll ans;
namespace ST
{
int s[N][W + 3];
void init()
{
fo(i, 1, n) s[i][0] = i;
fo(j, 1, lg[n])
fo(i, 1, n - p2[j] + 1)
{
int x = s[i][j - 1], y = s[i + p2[j - 1]][j - 1];
s[i][j] = sum[x] > sum[y] ? x : y;
}
}
inline int query(int l, int r)
{
int p = lg[r - l + 1];
int x = s[l][p], y = s[r - p2[p] + 1][p];
return sum[x] > sum[y] ? x : y;
}
}
struct Node
{
int p, l, r, w;
Node(){}
Node(int _p, int _l, int _r){p = _p, l = _l, r = _r, w = ST::query(l, r);}
inline int val() const {return sum[w] - sum[p - 1];}
bool operator<(const Node b) const
{
return val() < b.val();
}
};
priority_queue<Node> h;
int main()
{
freopen("fantasy.in", "r", stdin);
freopen("fantasy.out", "w", stdout);
n = read(), k = read(), L = read(), R = read();
fo(i, 1, W) p2[i] = p2[i - 1] << 1;
fo(i, 1, n) sum[i] = read() + sum[i - 1];
fo(i, 2, n) lg[i] = lg[i >> 1] + 1;
ST::init();
fo(i, 1, n - L + 1)
h.push(Node(i, i + L - 1, min(n, i + R - 1)));
fo(i, 1, k)
{
Node t = h.top(); h.pop();
ans += t.val();
if(t.l < t.w) h.push(Node(t.p, t.l, t.w - 1));
if(t.w < t.r) h.push(Node(t.p, t.w + 1, t.r));
}
printf("%lld", ans);
return 0;
}

JZOJ5409. Fantasy && Luogu2048 [NOI2010]超级钢琴的更多相关文章

  1. luogu2048 [NOI2010]超级钢琴 (优先队列+主席树)

    思路:先扫一遍所有点作为右端点的情况,把它们能产生的最大值加到一个优先队列里,然后每次从优先队列里取出最大值,再把它对应的区间的次大值加到优先队列里,这样做K次 可以用一个前缀和,每次找i为右端点的第 ...

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

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

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

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

  4. NOI2010超级钢琴 2

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. Linux基础命令---ab测试apache性能

    ab ab指令是apache的性能测试工具,它可以测试当前apache服务器的运行性能,显示每秒中可以处理多少个http请求. 此命令的适用范围:RedHat.RHEL.Ubuntu.CentOS.F ...

  2. Linux:sqlldr命令

    第一步:写一个 ctl格式的控制文件 CTL 控制文件的内容 : load data --1. 控制文件标识 infile 'xxx.txt' --2. 要导入的数据文件名 insert into t ...

  3. 【C/C++】链表

    #include <bits/stdc++.h> using namespace std; struct node { int data; // 数据 node* next; // 指针 ...

  4. C#生成pdf -- iText7 设置自定义字体和表格

    itextsharp已经不再更新,由iText 7来替代 安装 nuget 安装 itext7 注册自定义字体 下载字体文件 .ttc或.ttf到项目目录,设置更新则拷贝到输出目录,这样构建的时候会把 ...

  5. C#.NET编程小考30题错题纠错

    1)以下关于序列化和反序列化的描述错误的是( C). a) 序列化是将对象的状态存储到特定存储介质中的过程 b) 二进制格式化器的Serialize()和Deserialize()方法可以分别用来实现 ...

  6. [BUUCTF]PWN——hitcontraining_magicheap

    hitcontraining_magicheap 附件 步骤: 例行检查,64位程序,开启了nx和canary 本地试运行一下,经典的堆的菜单 64位ida载入,检索程序里的字符串的时候发现了后门 m ...

  7. CF1265B Beautiful Numbers 题解

    Content 给定一个 \(1\sim n\) 的排列,请求出对于 \(1\leqslant m\leqslant n\),是否存在一个区间满足这个区间是一个 \(1\sim m\) 的排列. 数据 ...

  8. LuoguP4419 [COCI2017-2018#1] Cezar 题解

    Content 有一个牌库,有一些点数为 \(1\sim 11\) 的牌,其中除了点数为 \(10\) 的牌有 \(16\) 张之外,其余点数的牌各有四张.现在玩一个游戏,已经拿出了 \(n\) 张牌 ...

  9. CF1491A K-th Largest Value 题解

    Content 你有一个长度为 \(n\),并且仅包含 \(0/1\) 的数组 \(a\).现在对这个序列做以下两种操作之一共 \(q\) 次: \(1\) \(x\):将 \(a_x\) 修改为 \ ...

  10. WebRTC本地插入多个转发节点

    网络延迟是一种比较常见的情况.在本地网页上,我们可以建立多个RTCPeerConnection,增加转发次数,来模拟出网络延迟的效果. 建立通话后,再往后面增加本地转发节点. 准备 页面准备,方便我们 ...