超级钢琴

有 \(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的更多相关文章

随机推荐

  1. MCU变量加载过程

    前言 在开发mcu代码的时候经常会有些疑惑,变量是怎么在编译之后进入单片机的ram区的呢,特别是在使用keil开发的时候.后来在接触gcc编译器和自研的mcu后,终于明白了这个问题.实际上变量编译后被 ...

  2. Python Revisited Day10 (进程与线程)

    目录 10.1 使用多进程模块 10.2 将工作分布到多个线程 <Python 3 程序开发指南>学习笔记 有俩种方法可以对工作载荷进行分布,一种是使用多进程,另一种是使用多线程. 10. ...

  3. IOS 如何获取app更新链接 如【itms-apps://itunes.apple.com/cn/app/id1362432761?mt=8】

    这是iTunes接口地址 ,有兴趣可以看一下,我们要用到的接口如下,xxx 处换成自己 App 的 AppId ,AppId 可以在 iTunes Connect 里面看到. http://itune ...

  4. 初遇NFT-IPFS

    初遇NFT-IPFS 本次学习如何使用Hardhat框架制作可预售的NFT并利用IPFS存储元数据. NFT简介 NFT全称Non-fungible Token(即非同质化通证).不可分割性(目前有碎 ...

  5. 使用 JavaScript自定义函数计算出教室的体积大小,其中教室的长、宽、高分别为 8 米、5 米、3 米

    查看本章节 查看作业目录 需求说明: 使用 JavaScript自定义函数计算出教室的体积大小,其中教室的长.宽.高分别为 8 米.5 米.3 米 实现思路: 创建 HTML 页面 在页面的 < ...

  6. MD5,SHA1及SHA256等哈希加密方法实现:Java,C#,Golang,Python

    哈希算法又称散列算法,它可以从任何数据中快速的创建一个凭证,而这个凭证很难被推倒出来,因为一丁点的变化会导致凭证的差别恨到,也就是说哈希算法具有不可逆性,因此它在密码数据校验方面用的很广,比如我们常用 ...

  7. python 中的省略号

    在查看django源码时遇到下列内容:sweat: 这个省略号是什么意思? 来自为知笔记(Wiz)

  8. BIO、NIO、AIO --- 个人理解

    1.前言 什么是 BIO.NIO.AIO  ,不难看出,都是共同的字符IO , IO的意思是input output  ,即输入输出 , 那么 B . N .A 分别指不同的io模型 ,而io又分为 ...

  9. antd中的form表单 initialValue导致数据不更新问题

    初步理解 : initialValue就是所谓的defaultValue,只会在第一次赋值的时候改变,却又有一些不同,因为 initialValue又会因其他改动而改变. 然而当获取的数据重新上来要渲 ...

  10. 新增访客数量MR统计之NewInstallUserMapper中维度信息准备

    关注公众号:分享电脑学习回复"百度云盘" 可以免费获取所有学习文档的代码(不定期更新)云盘目录说明:tools目录是安装包res 目录是每一个课件对应的代码和资源等doc 目录是一 ...