题目大意:让你求出这个串是否是近似有序串,什么叫做近似有序串呢,就是,这个串去掉任意一个字符也能保持有序。
算法思路:模板题,只需要求出最大的有序子串,然后看这个串总的长度-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; }