zoukankan      html  css  js  c++  java
  • JZOJ 5409 Fantasy & NOI 2010 超级钢琴 题解

    其实早在 2020-12-26 的比赛我们就做过 5409. Fantasy

    这可是紫题啊

    题目大意

    给你一个序列,求长度在 \([L,R]\) 区间内的 \(k\) 个连续子序列的最大和

    题解

    如此多的子序列并不好处理

    \(i\) 为一个区间的左端点,那么右端点的区间为 \([i+L-1,i+R-1]\) ,记前缀和为 \(sum_i\)

    那么一个区间 \([i,j]\) 的和就是 \(sum_j-sum_{i-1}\) 已经知道左端点 \(sum_i\) ,只要找到最大的 \(sum_j\) 即可

    所以可以用 \(\text{RMQ}\) 来解决查找问题。考虑把一个区间变成四元组 \(\{now,l,r,id\}\)

    表示左端点 \(i\) 的位置,右端点的区间,区间 \([l,r]\)\(j\) 的位置 。将一些四元组放入堆中

    每次将堆顶的拆成两个 \(\{now,l,id-1,id_1\},\{now,pos+1,r,id_2\}\)

    再放进堆中,原堆顶删除。\(id_1,id_2\) 都是 \(\text{RMQ}\) 实现,每次堆顶的值 \(sum_{id}-sum_{now-1}\) 的和就是答案

    Code

    #include<bits/stdc++.h>
    using namespace std;
    char buf[100000],*S=buf,*T=buf;
    inline char Gc() {
    	return S==T&&(T=(S=buf)+fread(buf,1,100000,stdin),S==T)?EOF:*S++;
    }
    inline int Rd() {
    	register int o=0,f=0;
    	static char c=Gc();
    	for(;c<'0'||c>'9';c=Gc()) f|=c==45;
    	for(;c>'/'&&c<':';c=Gc()) o=(o<<1)+(o<<3)+(c^48);
    	return f?-o:o;
    } 
    const int N=500005;
    typedef long long LL;
    int n,K,L,R,pw[35]={1},lg[N],sum[N],f[N][35];
    LL ans;
    inline int maxx(int x,int y) { return sum[x]>sum[y]?x:y; }
    inline int RMQ(int l,int r) {
    	register int k=lg[r-l+1];
    	return maxx(f[l][k],f[r-pw[k]+1][k]);
    }
    struct node {
    	int x,l,r,id; node() { }
    	inline node(int _x,int _l,int _r):x(_x),l(_l),r(_r),id(RMQ(_l,_r)) { }
    	inline bool operator<(const node &o) const {
    		return sum[id]-sum[x-1]<sum[o.id]-sum[o.x-1]; }
    }oo;
    priority_queue<node>heap;
    int main() {
    //	freopen("fantasy.in","r",stdin);
    //	freopen("fantasy.out","w",stdout);
    	for(int i=1;i<31;i++)pw[i]=pw[i-1]<<1;
    	n=Rd(),K=Rd(),L=Rd(),R=Rd();
    	for(int i=1;i<=n;i++)f[i][0]=i,sum[i]=sum[i-1]+Rd();
    	for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
    	for(int j=1;j<=lg[n];j++)
    		for(int i=0;i+pw[j-1]-1<=n;i++)
    			f[i][j]=maxx(f[i][j-1],f[i+pw[j-1]][j-1]);
    	for(int i=1;i<=n;i++)
    		if(i+L-1<=n)
    			heap.push(node(i,i+L-1,min(i+R-1,n)));
    	while(K--) {
    		oo=heap.top(),heap.pop(),ans+=1LL*sum[oo.id]-1LL*sum[oo.x-1];
    		if(oo.l^oo.id)heap.push(node(oo.x,oo.l,oo.id-1));
    		if(oo.id^oo.r)heap.push(node(oo.x,oo.id+1,oo.r));
    	}
    	printf("%lld",ans);
    }
    
  • 相关阅读:
    Attribute在.NET编程中的应用
    Attribute应用权限验证
    Enterprise Library: Configuration Application Block
    App_Themes
    C# DNN 地址
    c++函数参数类型引用、指针、值
    四川新华社 关于IT诗人代腾飞 新书《赢道:成功创业者的28条戒律》新闻报道
    30岁之前创业想成功必看
    大师指点—为人处世秘诀之快乐成功之道!
    四川经济日报 关于代腾飞 新书《赢道:成功创业者的28条戒律》新闻报道
  • 原文地址:https://www.cnblogs.com/KonjakLAF/p/14588861.html
Copyright © 2011-2022 走看看