题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5532
题意:
给出n个数,问如果去掉其中一个数,能否构成不上升或者不下降的序列。
题解:
求一边最长不上升子序列和最长不下降子序列,判断长度是否大于等于n-1即可。
需要用nlogn的算法,然而CDQ分治n*(logn)^2居然TLE了,我表示很惊讶,也可能是我的CDQ分支写的丑,或者说那根本就不是CDQ分治,欢迎各位帮我指出其优化。。。
代码:
CDQ TLE代码:
#include
#include
#include
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.xx;
else
return x1.wint 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<q(1,n);
if (dp[n]==n-1||dp[n]==n)
{
printf("Yes\n");
continue;
}
printf("No\n");
}
}
二分AC代码:
#include
#include
#include
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");
}
}