zoukankan      html  css  js  c++  java
  • A

    题目链接:https://vjudge.net/contest/202699#problem/A

    题意

      给一个n个元素的序列,从中挑出最长的子序列,要求子序列中元素差的最大值不超过k。问有几个最长子序列,子序列长度,以及这几个子序列的起始、终止位置。 

      n<=10e5,k<=10e6 

    题解

      很显然是水题。。

    方法1.rmq+二分查找

      很暴力很暴力的做法。若用st表维护时间复杂度为(nlogn),线段树(nlognlogn)

      即维护出每一段区间的最小最大值

      每次查找时确定头结点,二分尾节点

    方法2.滑动窗口+单调队列

      时间复杂度(n)

      很容易发现这是个滑动窗口问题,即固定左端点,向右延伸右端点

      若无法延伸,则移动左端点,而右端点维持原状

      其中当前区域内的最小值和最大值显然用单调队列维护

    代码

    方法1:

     1 #include<iostream> 
     2 #include<cstdio>
     3 typedef struct re {int x,h,t;};
     4 int a[200000],f[200000];
     5 re p1[2000000],p2[2000000];
     6 using namespace std;
     7 int n,k;
     8 void build1(int x,int h,int t)
     9 {  
    10   p1[x].h=h; p1[x].t=t;
    11   if (h==t)
    12   {
    13     p1[x].x=a[h]; return;
    14   }
    15   int mid=(h+t)/2;
    16   build1(x*2,h,mid); build1(x*2+1,mid+1,t);
    17   p1[x].x=max(p1[x*2].x,p1[x*2+1].x);
    18 }
    19 void build2(int x,int h,int t)
    20 {  
    21   p2[x].h=h; p2[x].t=t;
    22   if (h==t)
    23   {
    24     p2[x].x=a[h]; return;
    25   }
    26   int mid=(h+t)/2;
    27   build2(x*2,h,mid); build2(x*2+1,mid+1,t);
    28   p2[x].x=min(p2[x*2].x,p2[x*2+1].x);
    29 }
    30 int query1(int x,int h,int t)
    31 {
    32   if (p1[x].h>t || p1[x].t<h) return(0);
    33   if (h<=p1[x].h && p1[x].t<=t) return(p1[x].x);
    34   return(max(query1(x*2,h,t),query1(x*2+1,h,t))); 
    35 }
    36 int query2(int x,int h,int t)
    37 {
    38   if (p2[x].h>t || p2[x].t<h) return(11111111);
    39   if (h<=p2[x].h && p2[x].t<=t) return(p2[x].x);
    40   return(min(query2(x*2,h,t),query2(x*2+1,h,t))); 
    41 }
    42 bool check(int x,int y)
    43 {
    44   if (query1(1,x,y)-query2(1,x,y)<=k) return(true);
    45   else return(false);
    46 }
    47 main(){
    48   scanf("%d%d",&n,&k);
    49   for (int i=1; i<=n; i++)
    50     scanf("%d",&a[i]);
    51   build1(1,1,n);
    52   build2(1,1,n);
    53   int maxn=0;
    54   for (int i=1; i<=n; i++)
    55   {
    56     int h=0,t=n-i;
    57     while (h<t)
    58     {
    59       int mid=(h+t)/2+1;
    60       if (check(i,i+mid)) h=mid; else t=mid-1; 
    61     }
    62     f[i]=h+1; maxn=max(maxn,f[i]);
    63   }
    64   int cnt=0;
    65   for (int i=1; i<=n; i++) 
    66     if (f[i]==maxn) cnt++;
    67   printf("%d %d
    ",maxn,cnt);
    68   for (int i=1; i<=n; i++)
    69     if (f[i]==maxn) printf("%d %d
    ",i,f[i]+i-1);  
    70   return(0);
    71 }
  • 相关阅读:
    消息中间件(一)MQ详解及四大MQ比较
    WebSocket 详解教程
    Nginx 简易教程
    排序七 归并排序
    排序五 简单选择排序
    排序四 希尔排序
    排序二 快速排序
    排序一 冒泡排序
    [算法题] 人民币大小写转换(阿拉伯数字和汉字转换)
    Linux编程 18 安装软件程序(yum工具对软件包安装,删除,更新介绍)
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/7979354.html
Copyright © 2011-2022 走看看