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

    Portal --> bzoj2006

    Solution

      一开始看错题了。。没有看到编号连续然后愣了好久==

    ​  首先肯定是找最大的(K)个啦,然后具体怎么找的话。。没有什么特别好的办法那就暴力一点,每次取最大值然后把它删掉然后再取这样

    ​  现在的问题是怎么找最大值

    ​  注意到一个很重要的点,因为这题要求一个和弦的音符编号是连续的一段(一个区间),所以我们可以按照区间的左端点分类,每一类形如((st,l,r)),表示左端点为(st),右端点(in[l,r])的区间集合,显然,当前的最大值一定是每一类最大值的最大值,那么如果说我们知道了每一类的最大值之后,将所有的类全部丢进一个堆里面就好了,至于删除的话,如果说我们可以定位这个最大值具体是哪个区间(假设为([lx,rx])),那么我们只要把这个区间所在的类((st,l,r))先删掉,然后再把((st,l,lx-1))((st,rx+1,r))加进去就好了

    ​  那么最后的问题就是我们要寻求一种快速的计算((st,l,r))这类区间的最大值的办法

    ​  既然是区间求和。。那当然是用前缀和啊,然后发现因为对于一类区间来说,左端点是固定的,所以我们只要比较这类区间中右端点处的前缀和即可比较大小,所以我们直接ST表RMQ一下就好了,这样也能很方便地定位具体是哪个区间

    ​  具体实现的话,可以每个类多加一个参数(mx),表示这类区间中区间和最大的那个区间为([st,mx]),然后。。堆里面的话各类区间比较的时候根据(sum[mx]-sum[st-1])的大小比较就好了

      

    ​  mark:看清楚题目(是求和还是求第(K)大,是连续还是不连续,是否需要用long long)

    ​  mark:区间的问题的话。。是不是固定其中一点是套路。。?

      

    ​  代码大概长这个样子

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<cmath>
    #define ll long long
    using namespace std;
    const int N=500010,TOP=20;
    ll sum[N],a[N],mx[N][TOP+1];
    struct Data{
    	int st,l,r,mx;
    	Data(){}
    	Data(int st1,int l1,int r1,int mx1){st=st1; l=l1; r=r1; mx=mx1;}
    	friend bool operator < (Data x,Data y){return sum[x.mx]-sum[x.st-1]<sum[y.mx]-sum[y.st-1];}
    };
    priority_queue<Data> q;
    int n,m,L,R,K;
    ll ans;
    void prework(){
    	for (int i=1;i<=n;++i) mx[i][0]=i;
    	for (int j=1;j<=TOP;++j)
    		for (int i=n-(1<<j)+1;i>=1;--i)
    			if (sum[mx[i][j-1]]>sum[mx[i+(1<<j-1)][j-1]])
    				mx[i][j]=mx[i][j-1];
    			else 
    				mx[i][j]=mx[i+(1<<j-1)][j-1];
    }
    int get_mx(int l,int r){
    	int len=r-l+1,lg=(int)(log(1.0*len)/log(2.0));
    	if (sum[mx[l][lg]]>sum[mx[r-(1<<lg)+1][lg]]) return mx[l][lg];
    	return mx[r-(1<<lg)+1][lg];
    }
    void solve(){
    	Data tmp;
    	while (!q.empty()) q.pop();
    	for (int i=1;i+L-1<=n;++i)
    		q.push(Data(i,i+L-1,min(i+R-1,n),get_mx(i+L-1,min(i+R-1,n))));
    	ans=0;
    	for (int i=1;i<=K;++i){
    		if (q.empty()) break;
    		tmp=q.top(); q.pop();
    		ans+=sum[tmp.mx]-sum[tmp.st-1];
    		//printf("%d
    ",ans);
    		if (tmp.l<=tmp.mx-1)
    			q.push(Data(tmp.st,tmp.l,tmp.mx-1,get_mx(tmp.l,tmp.mx-1)));
    		if (tmp.mx+1<=tmp.r)
    			q.push(Data(tmp.st,tmp.mx+1,tmp.r,get_mx(tmp.mx+1,tmp.r)));
    	}
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
    	freopen("a.in","r",stdin);
    #endif
    	scanf("%d%d%d%d",&n,&K,&L,&R);
    	sum[0]=0;
    	for (int i=1;i<=n;++i) scanf("%lld",a+i),sum[i]=sum[i-1]+a[i];
    	prework();
    	solve();
    	printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    编程命名规范化
    傻孩子菜单框架(转)
    《数据结构》示范程序树的长子-兄弟表示法
    keil中编译时出现*** ERROR L107: ADDRESS SPACE OVERFLOW
    单片机C语言下LCD多级菜单的一种实现方法
    指针函数与函数指针的区别
    LCD1602汉字、自定义字符取模
    FFmpeg纯净版解码 av_parser_parse2
    ffmpeg 内存读写相关
    AudioSpecificConfig
  • 原文地址:https://www.cnblogs.com/yoyoball/p/9804832.html
Copyright © 2011-2022 走看看