zoukankan      html  css  js  c++  java
  • 【bzoj2006】 NOI2010—超级钢琴

    http://www.lydsy.com/JudgeOnline/problem.php?id=2006 (题目链接)

    题意

      给出一个数列,在其中选出K个长度在${[L,R]}$之间的不同的区间,使得他们的和权值和最大。

    Solution

      我们可以先处理处它的前缀和${sum}$,然后用ST表维护前缀和的区间最小值。做完这些预处理以后,我们从L for 到n,每次在区间${[i-R,i-L]}$中取出前缀和最小的${sum[M]}$,与${sum[i]}$相减,丢入堆中。之后我们每次取出堆顶元素加入答案,并分别找出区间${[i-R,M-1]}$和${[M+1,i-L]}$的前缀和最小的${sum[M1],sum[M2]}$,分别相减,丢入堆中。以此类推,直到取出${K}$个元素为止。

    代码

    // bzoj2006
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    #define LL long long
    #define inf 2147483640
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
    inline int getint() {
    	int x=0,f=1;char ch=getchar();
    	while (ch>'9' || ch<'0') {if (ch=='-') f=-1;ch=getchar();}
    	while (ch>='0' && ch<='9') {x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    
    const int maxn=500010;
    struct data {
    	int l,r,m,i;LL w;
    	friend bool operator < (const data &a,const data &b) {
    		return a.w<b.w;
    	}
    };
    priority_queue<data> q;
    int ST[maxn][30],bin[30],a[maxn],Log[maxn];
    LL s[maxn];
    int n,K,L,R;
    
    inline int mina(register int x,register int y) {
    	return s[x]<s[y] ? x : y;
    }
    inline int query(register int l,register int r) {
    	int k=Log[r-l+1];
    	return mina(ST[l][k],ST[r-bin[k]+1][k]);
    }
    int main() {
    	bin[0]=1;for (int i=1;i<=19;i++) bin[i]=bin[i-1]<<1;
    	n=getint(),K=getint(),L=getint(),R=getint();
    	for (int i=1;i<=n;i++) s[i]=getint(),s[i]+=s[i-1];
    	for (int i=1;i<=n;i++) ST[i][0]=i;
    	for (int i=2;i<=n;i++) Log[i]=Log[i>>1]+1;
    	for (int j=1;j<=19;j++)
    		for (int i=0;i+bin[j]<=n+1;i++)
    			ST[i][j]=mina(ST[i][j-1],ST[i+bin[j-1]][j-1]);
    	for (int i=L;i<=n;i++) {
    		int l=max(i-R,0),r=i-L;
    		int x=query(l,r);
    		q.push((data){l,r,x,i,s[i]-s[x]});
    	}
    	LL ans=0;
    	while (K--) {
    		data t=q.top();ans+=t.w;q.pop();
    		if (t.l<t.m) {
    			int x=query(t.l,t.m-1);
    			q.push((data){t.l,t.m-1,x,t.i,s[t.i]-s[x]});
    		}
    		if (t.m<t.r) {
    			int x=query(t.m+1,t.r);
    			q.push((data){t.m+1,t.r,x,t.i,s[t.i]-s[x]});
    		}
    	}
    	printf("%lld",ans);
    	return 0;
    }
    

      

      

  • 相关阅读:
    转:细说一个汉字等于几个字符,以及汉字,字符,字节,位之间的关系
    iOS8 无缝切换WKWebView,借鉴IMYWebview,解决进度条,cookie,本地页面等问题
    ios加载本地html
    如何做一个细心的人
    学习h5(开始)
    JLRoute 使用
    大二下学期学习进度(四)
    求首尾相接的数组的最大子数组和
    大二下学期学习进度(三)
    构建之法阅读笔记01
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/5947132.html
Copyright © 2011-2022 走看看