Luogu_P2048
超级钢琴
有 \(n\) 个音符,编号从 \(1\) 到 \(n\) 。第 \(i\) 个音符的美妙度为 \(A_i\) 。
我们要找到 \(k\) 段不同超级和弦组成的乐曲,每段乐曲的连续音符个数 \(x\) 满足 \(L \le x \le R\) , 求乐曲美妙度的最大值。
注:当且仅当这两个超级和弦所包含的音符集合是相同的。
Solution
我们定义 \(f_{idx,l,r}\) 为左端点为 \(idx\) ,右端点在 \(L \le right \le R\) 区间内的最大值。
我们可以先求出对于每个左端点 \(idx\) ,长度为 \(L \le x \le R\) 中的超级和弦组成的乐曲中的最大值。求出之后我们可以知道,所有符合条件的乐曲美妙度的最大值一定是上面求的所有值中的最大值。 假设 \(f_{idx,l,r}\) 是我们当前求得的最大值,并且取得最大值的右端点为 \(right\)
那么以 \(idx\) 为左端点的区间就可以分裂为 \(f_{idx,l, right - 1}\) 和 \(f_{idx, right + 1, r}\) ,即是对于左端点 \(idx\) 我们把右端点 \(right\) 这个可能性删去。
那么我们考虑维护一个优先队列,先把所有左端点的可能性放进堆中,每次取出堆顶,然后把堆顶分裂,继续加入堆中,当我们取出 k 次之后,就得到了答案。
现在有个问题是怎么求出对于 \(f_{idx,l,r}\) 取得最大值的右端点 \(right\) ,本题的查询是离线,那么我们可以考虑用 ST表 预处理出 \([l,r]\) 区间内的前缀和的最大值的下标。 这样我们既可以求得 \(right\) 又可以求得 最大值 \(s[right] - s[idx - 1]\) 。
CODE
const int N = 5e5 + 10;
int n, k, l, r;
int a[N], s[N];
int f[N][20];
inline void init() {
for(int i = 1; i <= n; i ++ ) f[i][0] = i;
for(int j = 1; (1 << j) <= n; j ++ )
for(int i = 1; i + (1 << j) - 1 <= n; i ++ ){
int x = f[i][j - 1], y = f[i + (1 << (j - 1))][j - 1];
f[i][j] = s[x] >= s[y] ? x : y;
}
}
inline int query(int l, int r ) {
int k = log(r - l + 1) / log(2);
int x = f[l][k], y = f[r - (1 << k) + 1][k];
return s[x] >= s[y] ? x : y;
}
struct node {
int i, l, r, nw;
bool operator < (const node &t) const {
if(t.nw != nw)
return t.nw > nw;
if(t.i != i)
return t.i > i;
if(t.l != l)
return t.l > l;
return t.r > r;
}
};
priority_queue<node> q;
inline void solve() {
scanf("%d%d%d%d", &n, &k, &l, &r);
for(int i = 1; i <= n; i ++ ) { scanf("%d", &a[i]); s[i] = s[i - 1] + a[i]; }
init();
node res;
for(int i = 1; i <= n; i ++ ) {
res.i = i; res.l = i + l - 1, res.r = min(n, i + r - 1);
if(res.l > n) break;
res.nw = s[query(res.l, min(n, res.r))] - s[i - 1];
q.push(res);
}
LL ans = 0;
int cnt = 0;
while(q.size()) {
auto t = q.top(); q.pop();
ans += t.nw;
cnt ++;
if(cnt >= k) break;
int p = query(t.l, t.r);
if(p > t.l) {
q.push({t.i, t.l, p - 1, s[query(t.l, min(n, p - 1))] - s[t.i - 1]});
}
if(p < t.r) {
q.push({t.i, p + 1, t.r, s[query(p + 1, min(n, t.r))] - s[t.i - 1]});
}
}
printf("%lld\n", ans);
}
Luogu_P2048的更多相关文章
随机推荐
- 第四十七个知识点:什么是Fiat-Shamir变换?
第四十七个知识点:什么是Fiat-Shamir变换? 只要Alice和Bob同时在线,Sigma协议能快速的完成Alice向Bob证明的任务.Alice向Bob发送承诺,Bob返回一个挑战,最后Ali ...
- Class Activation Mapping (CAM)
目录 概 主要内容 CAM Grad-CAM Grad-CAM++ Score-CAM 最后 代码 Zhou B., Khosla A., Lapedriza A., Oliva A. and Tor ...
- WPF之AvalonEdit实现MVVM双向绑定
AvalonEdit简介 AvalonEdit是基于WPF开发的代码显示控件,默认支持多种不同语言的关键词高亮,并且可以自定义高亮配置.所以通过AvalonEdit可以快速开发出自己想要的代码编辑器. ...
- [C++]高效C/C ++编程tips
Effective C++ 视C++ 为一个语言联邦(C.Object-Oriented C++.Template C++.STL) 宁可以编译器替换预处理器(尽量以const.enum.inline ...
- [opencv]findcoutours函数使用
轮廓是定义或限定形状或对象的边或线,是机器视觉中的常用的概念,多用于目标检测.识别等任务. 关于OpenCV轮廓操作,尤其是级别及如何使用轮廓级别进行筛选等问题,相关文章比较少,正好最近用到,因此将其 ...
- 主席树(区间第k小的数)
题目链接: https://www.luogu.org/problem/P3834 首先要离散化,然后主席树模板. 1 #include<cstdio> 2 #include<cst ...
- 新手入门typeScript
强类型与弱类型(类型安全) 强类型不允许随意的隐士类型转换,而弱类型是允许的 变量类型允许随时改变的特点,不是强弱类型的差异 静态类型与动态类型(类型检查) 静态类型:一个变量声明时它的类型就是明确的 ...
- HTMl+CSS 模仿京东网登录页面
课后实践项目,仅页面效果,写博客纯属记录! 码云开源仓库地址:https://gitee.com/ynavc/jd 演示地址:https://ynavc.gitee.io/jd 效果图: 实现代码: ...
- VMware客户端vSphereClient新建虚拟机
1.说明 VMware客户端工具vSphere Client, 用来连接和管理ESX或ESXi主机(下面称为宿主机), 可以方便的创建.管理虚拟机,并分配相应的资源.宿主机就是使用虚拟化软件运行虚拟机 ...
- 【操作系统】I/O多路复用 select poll epoll
@ 目录 I/O模式 I/O多路复用 select poll epoll 事件触发模式 I/O模式 阻塞I/O 非阻塞I/O I/O多路复用 信号驱动I/O 异步I/O I/O多路复用 I/O 多路复 ...