【hdu5532】【 2015ACM/ICPC亚洲区长春站】Almost Sorted Array题意&题解&代码

题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5532
题意:
给出n个数,问如果去掉其中一个数,能否构成不上升或者不下降的序列。
题解:
求一边最长不上升子序列和最长不下降子序列,判断长度是否大于等于n-1即可。
需要用nlogn的算法,然而CDQ分治n*(logn)^2居然TLE了,我表示很惊讶,也可能是我的CDQ分支写的丑,或者说那根本就不是CDQ分治,欢迎各位帮我指出其优化。。。
代码:
CDQ TLE代码:

#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;
int T,n,m,a[100005],b[100005],dp[100005];
struct node{
    int w;int x; 
}q[100005];
int cmp(node x1,node x2)
{
    if (x1.x!=x2.x)
    return x1.x<x2.x;
    else
    return x1.w<x2.w;
}
void work(int l,int mid,int r)
{
    int tot=0;
    for (int i=l;i<=r;i++)
    {
        tot++;
        q[tot].x=a[i];
        q[tot].w=i;
    }
    sort(q+1,q+1+tot,cmp);
    int m=0;
    for (int i=1;i<=tot;i++)
    {
        if (q[i].w<=mid)
        m=max(m,dp[q[i].w]);
        else
        dp[q[i].w]=max(dp[q[i].w],m+1);
    }
}
void cdq(int l,int r)
{
    if (l>=r)return ;
    int mid=(l+r)/2;
    cdq(l,mid);
    work(l,mid,r);
    cdq(mid+1,r);
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for (int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            dp[i]=1;
            b[i]=a[i];
        }
        cdq(1,n);
        if (dp[n]==n-1||dp[n]==n)
        {
            printf("Yes\n");
            continue;
        }
        for (int i=1,j=n;i<=n;i++,j--)
        {
            a[i]=b[j];
            dp[i]=1;
        }
        //for (int i=1;i<=n;i++)
        //cout<<a[i]<<endl;
        cdq(1,n);
        if (dp[n]==n-1||dp[n]==n)
        {
            printf("Yes\n");
            continue;
        }
        printf("No\n");
    }
}

二分AC代码:

#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;
int T,n,m,len,a[100005],b[100005],c[100005];
int find(int L,int R,int x)
{
    if(L==R) return L;
    int mid=(L+R)/2;
    if(c[mid]<=x) return find(mid+1,R,x);
    else return find(L,mid,x);
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for (int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            b[i]=a[i];
            c[i]=0;
        }
        len=0;
        for(int i=1;i<=n;i++)
            {
            int j;
                    if(a[i]>=c[len]) len++,j=len;
                    else j=find(1,len,a[i]);
                    c[j]=a[i];
            }
        if (len==n-1||len==n)
        {
            printf("YES\n");
            continue;
        }
        for (int i=1,j=n;i<=n;i++,j--)
        {a[i]=b[j];c[i]=0;
        }   
        len=0;
        for(int i=1;i<=n;i++)
            {
            int j;
                    if(a[i]>=c[len]) len++,j=len;
                    else j=find(1,len,a[i]);
                    c[j]=a[i];
            }
        if (len==n-1||len==n)
        {
            printf("YES\n");
            continue;
        }
        printf("NO\n"); 
    }
}

你可能感兴趣的:(dp,最长上升子序列,2015ACM)