zoukankan      html  css  js  c++  java
  • UVALive

    这里写图片描述

    题意:给你一个序列,移除一个元素之后是一个非严格递增或非严格递减序列输出YES,否则输出NO,因为元素个数n有1e5个,因此n*n的最长递增子序列算法并超时,这里用二分来优化,得到n*logn的最长递增递减子序列算法。
    思路:计算最长递增和最长递减子序列长度,若子序列长度有一个+1后大于等于原序列长度则说明可以通过取出一个元素达到完全递增或递减的要求,否则输出NO

    n*logn的算法中,遍历一次原序列来插入和选择元素,logn的复杂度来自于插入元素时二分查找该元素应该代替的元素位置。
    相当于如何增加结果(最长递增子序列的长度)呢?每次增加这个flagmax的大小,就是新遍历到的这个元素a【i】比maxn最长序列数组中的最后一个值大,即可增加最长序列长度。因此是否增加长度取决于最后一个元素大小,那么为什么要不断将不满足条件的元素插入回最长序列数组中呢,明明在更新长度的过程中根本不会比对到这些插回的数。
    因为我每次遍历的新数a[i]要大于等于末尾最大值才能增加最长序列长度,我为了找到最长序列,应该使这个末尾元素尽可能小,才有不断增加长度的可能,那么我就应该更新这个最末尾元素,更新得越小越好,那么找到将较小元素插回,代替的操作,就将有可能更新到这个最末尾元素,注意,这仅仅是有机会更新到,并不是每一个插入代替操作都能更新最末尾的最大值。
    当我遇到比末尾元素大的值,增加子序列长度,否则,利用这个值来更新我的子序列各个值,达到促使末尾元素和整体序列各个元素变小的目的

    #include<stdio.h>///n*log(n)优化最长递增(递减)子序列
    #include<string.h>
    int t,a[100008],maxn[100008],minn[100008];
    int Search(int num,int low,int high)///递增序列中二分查找插入位置
    {
        int mid;
        while(low<=high)
        {
            mid=(low+high)/2;
            if(num>=maxn[mid]) low=mid+1;
            else high=mid-1;
        }
        return low;
    }
    int Search1(int num,int low,int high)///递减序列中二分查找插入位置
    {
        int mid;
        while(low<=high)
        {
            mid=(low+high)/2;
            if(num<=minn[mid]) low=mid+1;
            else high=mid-1;
        }
        return low;
    }
    int main()
    {
        int i,j,n;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d",&n);
            for(i=1;i<=n;i++)
            {
                scanf("%d",&a[i]);
            }
            maxn[1]=a[1];
            minn[1]=a[1];
            int flagmax=1,flagmin=1;///最长递增和递减子序列长度
            for(i=2;i<=n;i++)///相当于数组中存的是每个递增(递减)序列的最大值/最小值
            {
                if(a[i]>=maxn[flagmax])///如果当前遍历的数i符合严格递增要求,比目前最大值还大
                {
                    flagmax++;///最长子序列长度增加
                    maxn[flagmax]=a[i];///将这个较大数增加到最长序列末尾,作为这个选择的最长子序列中目前最大值
                }
                else///否则将这个数代替掉一个原最长序列中的一个数,这个筛出来的序列仍保持递增
                {
                    int pos=Search(a[i],1,flagmax);///递增序列中二分查找
                    maxn[pos]=a[i];
                }
                if(a[i]<=minn[flagmin])
                {
                    flagmin++;
                    minn[flagmin]=a[i];
                }
                else
                {
                    int pos=Search1(a[i],1,flagmin);///递减序列中二分查找
                    minn[pos]=a[i];
                }
            }///最终最长和
    //        printf("=======%d   %d
    ",flagmax,flagmin);
            if(flagmin+1>=n||flagmax+1>=n)///最后无论是递增满足还是递减满足,都能输出yes
            {
                printf("YES
    ");
            }
            else
            {
                printf("NO
    ");
            }
        }
    }
    
  • 相关阅读:
    平时十二测
    无题十四
    暑假第十测
    无题十三
    noip错题集
    无题十二
    BZOJ整理
    志愿者招募
    修车
    任务安排
  • 原文地址:https://www.cnblogs.com/kuronekonano/p/11794321.html
Copyright © 2011-2022 走看看