http://acm.split.hdu.edu.cn/showproblem.php?pid=5532
题意:由n个数组成的序列,如果去掉一个数后仍保持非递增或者非递减,则输出YES,否则输出NO.
思路:只需要求最长非递增子序列的长度和最长非递减子序列的长度,如果其中一个长度+1>=n,说明可以实现。(注意:用O(n*n)的算法会导致tle,此处用的是O(nlogn)的算法)
#include<stdio.h> #define N 100010 int num[N],end1[N],end2[N]; int find1(int flag,int *end,int low,int high) {//end1数组按非递减顺序存储每一位的最小值 int mid; while(low < high) { mid = (low+high)>>1; if(end[mid] > flag) high = mid; else low = mid + 1; } return low; } int find2(int flag,int *end,int low,int high) {//end2数组按非递增顺序存储每一位的最大值 int mid; while(low < high) { mid = (low+high)>>1; if(end[mid] >= flag) low = mid+1; else high = mid; } return low; } int main() { int t,n,i,j,ans,len1,len2; scanf("%d",&t); while(t--) { scanf("%d",&n); for(i = 1; i <= n; i ++) scanf("%d",&num[i]); end1[1] = end2[1] = num[1]; len1 = len2= 1; for(i = 2; i <= n; i ++) { if(num[i] >= end1[len1])//最长非递减 ans = ++len1; else ans = find1(num[i],end1,1,len1+1); end1[ans] = num[i]; if(num[i] <= end2[len2])//最长非递增 ans = ++len2; else ans = find2(num[i],end2,1,len2+1); end2[ans] = num[i]; } if(len1 + 1== n||len2 + 1== n||len1==n||len2==n) printf("YES\n"); else printf("NO\n"); } return 0; }