zoukankan      html  css  js  c++  java
  • hdu3530 Subsequence

    Problem Description
    There is a sequence of integers. Your task is to find the longest subsequence that satisfies the following condition: the difference between the maximum element and the minimum element of the subsequence is no smaller than m and no larger than k.
     

    Input
    There are multiple test cases.
    For each test case, the first line has three integers, n, m and k. n is the length of the sequence and is in the range [1, 100000]. m and k are in the range [0, 1000000]. The second line has n integers, which are all in the range [0, 1000000].
    Proceed to the end of file.
     

    Output
    For each test case, print the length of the subsequence on a single line.
     

    Sample Input
    5 0 0 1 1 1 1 1 5 0 3 1 2 3 4 5
     

    Sample Output
    5

    4

    这题我用的是rmq算法,先初始化2的次方的区间最大值最小值,然后循环算出最大的区间长度。

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #include<map>
    #include<string>
    using namespace std;
    int a[100006];
    int minx[100100][30];
    int maxx[100100][30];
    void init_rmq(int n)
    {
    	int i,j;
    	for(i=1;i<=n;i++)maxx[i][0]=minx[i][0]=a[i];
    	for(j=1;j<=20;j++){
    		for(i=1;i<=n;i++){
    			if(i+(1<<j)-1<=n)
    			{maxx[i][j]=max(maxx[i][j-1],maxx[i+(1<<(j-1))][j-1]);
    			minx[i][j]=min(minx[i][j-1],minx[i+(1<<(j-1))][j-1]);}
    		}
    	}
    }
    
    int getmax(int l,int r)
    {
    	int k,i;
    	if(l>r)swap(l,r);
    	k=(log((r-l+1)*1.0)/log(2.0));
    	return max(maxx[l][k],maxx[r-(1<<k)+1][k]);
    }
    
    int getmin(int l,int r)
    {
    	int k,i;
    	if(l>r)swap(l,r);
    	k=(log((r-l+1)*1.0)/log(2.0));
    	return min(minx[l][k],minx[r-(1<<k)+1][k]);
    }
    
    int main()
    {
    	int n,m,i,j,k,l,r,ans,t;
    	while(scanf("%d%d%d",&n,&m,&k)!=EOF)
    	{
    		for(i=1;i<=n;i++){
    			scanf("%d",&a[i]);
    		}
    		init_rmq(n);
    		l=1;ans=0;           //l不用每次从1开始判,因为之前的l越小,r-l+1的值就越大。
    		for(i=1;i<=n;i++){
    			r=i;
    			if(l>r)continue;
    			while(getmax(l,r)-getmin(l,r)>k)l++; //如果大于k,那么后面的r对于此时的l肯定不满足不大于k,所以必须l++;
    			if(getmax(l,r)-getmin(l,r)>=m && getmax(l,r)-getmin(l,r)<=k)ans=max(ans,r-l+1);
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    }<pre name="code" class="cpp">
    


    今天又用单调队列做了一下,想了很长时间,一开始一直想不明白。先设两个单调队列q1,q2分别记录最大值和最小值,设定一个起始点last,之后last=0只能不断向后移动,每加入一个数,判断q2[front2][0]-q1[front1][0]的值是不是大于k,如果大于那么移除q1[front1][1].q2[front2][1]中较小的(这里我差不多想了一个晚上(汗),我一直搞不懂为什么每次都要去掉序号排在前面的,后来想了想发现因为序列是连续的,如果先去掉的是序号大,那么序号小的必定会去掉,和时间的原理差不多),然后每次last记录min(q1[front1][1],q2[front2][1]),等到一个合适的值,再判断。

    </pre><pre name="code" class="cpp">
    
    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #include<map>
    #include<string>
    #define maxn 100005
    #define inf 88888888
    using namespace std;
    int a[maxn],q1[maxn][2],q2[maxn][2];
    int main()
    {
    	int n,m,i,j,k,front1,rear1,front2,rear2,last,num;
    	while(scanf("%d%d%d",&n,&m,&k)!=EOF)
    	{
    		for(i=1;i<=n;i++)scanf("%d",&a[i]);
    		num=0;last=0;     //last从0开始 
    		front1=front2=1;rear1=rear2=0;
    		for(i=1;i<=n;i++){
    			while(front1<=rear1 && q1[rear1][0]>=a[i])rear1--;   //不加也行 
    			rear1++;
    			q1[rear1][0]=a[i];q1[rear1][1]=i;
    			while(front2<=rear2 && q2[rear2][0]<=a[i])rear2--;
    			rear2++;
    			q2[rear2][0]=a[i];q2[rear2][1]=i;
    			//last=min(q1[front1][1],q2[front2][1]);这里不能加,会错,因为如果上一循环中的last比min(q2[front2][1],q1[front1][1])小,但last满足m<=q2[front2][0]-q1[front1][0]<=k,结果就缩小了。 
    			while(front1<=rear1 && front2<=rear2 && q2[front2][0]-q1[front1][0]>k){
    				if(q2[front2][1]>q1[front1][1])last=q1[front1++][1];
    				else last=q2[front2++][1];
    			}
    			if(q2[front2][0]-q1[front1][0]>=m){
    				if(i-last>num)num=i-last;
    			}
    		}
    		printf("%d
    ",num);
    	}
    	return 0;
    }

    又用线段树的方法写了一下,1A感觉很不错(笑),感觉三种方法的原理是一样的。

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #include<map>
    #include<string>
    using namespace std;
    #define maxn 100005
    #define inf 88888888
    int maxx,minx,minzuo,maxzuo;
    int a[maxn];
    struct node{
    	int l,r,max,min,minzuo,maxzuo;
    }b[4*maxn];
    void build(int l,int r,int i)
    {
    	int mid;
    	b[i].l=l;b[i].r=r;
    	if(l==r){
    		b[i].max=a[l];b[i].min=a[l];
    		b[i].maxzuo=b[i].minzuo=l;
    		return;
    	}
    	mid=(l+r)/2;
    	build(l,mid,i*2);
    	build(mid+1,r,i*2+1);
    	if(b[i*2].max>b[i*2+1].max){
    		b[i].max=b[i*2].max;
    		b[i].maxzuo=b[i*2].maxzuo;
    	}
    	else{
    		b[i].max=b[i*2+1].max;
    		b[i].maxzuo=b[i*2+1].maxzuo;
    	}
    	
    	if(b[i*2].min<b[i*2+1].min){
    		b[i].min=b[i*2].min;
    		b[i].minzuo=b[i*2].minzuo;
    	}
    	else{
    		b[i].min=b[i*2+1].min;
    		b[i].minzuo=b[i*2+1].minzuo;
    	}
    }
    
    void question(int l,int r,int i)
    {
    	int mid;
    	if(b[i].l==l && b[i].r==r){
    		if(maxx<b[i].max){
    			maxx=b[i].max;maxzuo=b[i].maxzuo;
    		}
    		if(minx>b[i].min){
    			minx=b[i].min;minzuo=b[i].minzuo;
    		}
    		return;
    	}
    	mid=(b[i].l+b[i].r)/2;
    	if(r<=mid)question(l,r,i*2);
    	else if(l>mid)question(l,r,i*2+1);
    	else{
    		question(l,mid,i*2);
    		question(mid+1,r,i*2+1);
    	}
    }
    
    int main()
    {
    	int n,m,i,j,k,last,num;
    	while(scanf("%d%d%d",&n,&m,&k)!=EOF)
    	{
    		for(i=1;i<=n;i++)scanf("%d",&a[i]);
    		build(1,n,1);
    		last=0;num=0;maxzuo=minzuo=0;
    		for(i=1;i<=n;i++){
    			while(1){
    				maxx=-inf;minx=inf;
    				if(last>=i)break;
    				question(last+1,i,1);
    				if(maxx-minx>k){
    				   if(minzuo<maxzuo)last=minzuo;
       				   else last=maxzuo;
    				}
    				else break;
    			}
    			if(maxx-minx>=m && last<i){
    				if(num<i-last)num=i-last;
    			}
    		}
    		printf("%d
    ",num);
    	}
    	return 0;
    }


    
    
  • 相关阅读:
    PHP5中PDO的简单使用
    Apache中设置默认首页的方法
    PHP数组读取的循环操作
    header("Location:login.php")应该注意的几个问题
    纯JavaScript实现弹出选择第几个单选按钮
    PHP关于错误抑制符@的使用
    CSS盒子模型
    Appache中的ServerAlias
    PHP move_uploaded_file() 函数 定义和用法
    PHP ob_start() 函数介绍
  • 原文地址:https://www.cnblogs.com/herumw/p/9464798.html
Copyright © 2011-2022 走看看