题目大意:让你求出这个串是否是近似有序串,什么叫做近似有序串呢,就是,这个串去掉任意一个字符也能保持有序。
算法思路:模板题,只需要求出最大的有序子串,然后看这个串总的长度-1是否小于等于最大有序子串的长度,如果不满足,则说明这个串不是近似串。如何求最大有序子串呢,就比较一下最长不上升子序列的长度和最长不下降子序列的长度,取最长的即可。
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define MAXN 100050
#define INF 0x3f3f3f3f
int t,a[MAXN],ans[MAXN],d[MAXN],S[MAXN],n;
int BSearch(int x, int y, int v) //二分求上界(不上升)
{
while(x <= y)
{
int mid = x+(y-x)/2;
if(S[mid] >= v) x = mid+1;
else y = mid-1;
}
return x;
}
int BSearch2(int x, int y, int v) //二分求上界(不下降)
{
while(x <= y)
{
int mid = x+(y-x)/2;
if(S[mid] <= v) x = mid+1;
else y = mid-1;
}
return x;
}
int LIS()//最长不下降子序列
{
memset(d,0,sizeof(d));
for(int i = 1; i <=n; i++) S[i] = INF;
int res = 0;
for(int i = 1; i <= n; i++)
{
int x = 1, y = i;
int pos = BSearch2(x, y, a[i]);
d[i] = pos;
S[d[i]] = min(S[d[i]], a[i]);
res = max(res, d[i]);
}
return res;
}
int LFS()//最长不上升子序列
{
for(int i = 1; i <=n; i++) S[i] = -INF; //注意初始值
memset(d, 0, sizeof(d));
int res = 0;
for(int i = 1; i <= n; i++)
{
int x = 1, y = i;
int pos = BSearch(x, y, a[i]);
d[i] = pos;
S[d[i]] = max(S[d[i]], a[i]);
res = max(res, d[i]);
}
return res;
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
}
int len1=LIS();//nlogn
int len2=LFS();//nlogn
int flag=max(len1,len2);
if(n-1<=flag)
{
printf("YES\n");
}
else
{
printf("NO\n");
}
}
return 0;
}
这里顺便补充一下,最长上升子序列和最长下降子序列的模板,过几天就去比赛了,记录一下。
#include<cstdio>
#include<cstring>
#define MAXN 40005
int arr[MAXN],ans[MAXN],len;
int binary_search(int i)
{
int left,right,mid;
left=0,right=len;
while(left<right)
{
mid = left+(right-left)/2;
if(ans[mid]>=arr[i]) right=mid;
else left=mid+1;
}
return left;
}
int main()
{
int T,p,i,j,k;
scanf("%d",&T);
while(T--)
{
scanf("%d",&p);
for(i=1; i<=p; ++i)
scanf("%d",&arr[i]);
ans[1] = arr[1];
len=1;
for(i=2; i<=p; ++i)
{
if(arr[i]<ans[len]) //这个是求最长上升子序列,如果是求下降的话,改成小于号即可
ans[++len]=arr[i];
else
{
int pos=binary_search(i);
ans[pos] = arr[i];
}
}
printf("%d\n",len);
}
return 0;
}