2022春每日一题:Day 40
题目:[NOI2010] 超级钢琴
前求出美妙值的前缀和,然后倍增处理一下前缀和的最大值,然后对于一个左端点s,他能取到右端点的只有s+l到s+r,而他的最大贡献就是s+l 到s+r的最大子段和,因此可以直接维护,然后用个堆维护总和最大值,这道题就做完了。
代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#define int long long
const int N=5e5+5;
using namespace std;
int n,m,L,R,f[N][20],a[N],sum[N],lg[N];
namespace ST
{
void init()
{
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
{
int s1=f[i][j-1],s2=f[i+(1<<(j-1))][j-1];
if(sum[s1]>=sum[s2])
f[i][j]=s1;
else
f[i][j]=s2;
}
}
int query(int l,int r)
{
int j=lg[r-l+1];
int s1=f[l][j],s2=f[r-(1<<j)+1][j];
if(sum[s1]>=sum[s2])
return s1;
else
return s2;
}
}
using namespace ST;
struct pos
{
int o,l,r,val,maxp;
pos(int oo,int ll,int rr)
{
o=oo;l=ll;r=rr;
maxp=query(l,r);
val=sum[maxp]-sum[o-1];
}
pos(){
}
friend bool operator < (pos a,pos b)
{
return a.val<b.val;
}
};
priority_queue <pos> q;
signed main()
{
scanf("%lld %lld %lld %lld",&n,&m,&L,&R);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
f[i][0]=i;
sum[i]=sum[i-1]+a[i];
}
for(int i=2;i<=n;i++)
lg[i]=lg[i>>1]+1;
init();
for(int i=1;i<=n;i++)
if(i+L-1<=n)
q.push(pos(i,i+L-1,min(i+R-1,n)));
int ret=0;
for(int i=1;i<=m;i++)
{
pos now=q.top();
q.pop();
ret+=now.val;
if(now.maxp-1>=now.l)
q.push(pos(now.o,now.l,now.maxp-1));
if(now.maxp+1<=now.r)
q.push(pos(now.o,now.maxp+1,now.r));
}
printf("%lld\n",ret);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话