POJ 1836 双边最长上升子序列
马草AC了简直是各种爽啊,而且算法里只用了两次LIS,算法整体复杂度O(nlogn)
真的是应了老乔那句至简至繁至简,思考了一整天,还是直接用两次LIS外加两个辅助数组就解决了问题
思路就是,要真的深入地思考清楚这个问题,真的深入理解了LIS而不仅仅是套模板,套模板的结果就是把复杂度弄成O(n^2logn)
首先一点,题目要求是,只要最终队列里的人能够看到队列两端的至少一端。
其次,一个细节问题需要注意,队列中最高的人可以有两个,如下图
接下来就是具体算法了,思路就是枚举每一个士兵arr[i], 看要剔除多少个人才能形成上图所示队列;
然后选出剔除人数最少的那一种。
arr[0] ... arr[i] ... arr[i+1] ... arr[n-1]
也就是说,对于arr[i],分别要对arr[0] ... arr[i] 和 arr[n-1] ... arr[i+1] 进行一次LIS,并且LIS的过程中每个士兵的height都不能超过arr[i]的height ———思路1
如果不再深入思考的话,根据这个思路算法看起来就是,一层循环,循环里套两个LIS,这也是网上大多数人的做法
但是我要告诉你,两次LIS外加两个数组记录状态就OK了,之后再用一个循环去结果里找出最佳的结果 ———思路2
你真的理解LIS了麽?
在一次队列的LIS中,当LIS进行到arr[i]的时候,LIS的结果数组res中已经记录了arr[0]到arr[i-1]LIS的结果
所以处理arr[i]的时候,是不是用数组记录一下LIS中二分的结果,就是思路1的循环中的LIS想要的结果呢?
如果看懂这一句话的时候,你就可以直接看我的代码了
1 #include<stdio.h> 2 #include<iostream> 3 using namespace std; 4 5 #include<math.h> 6 #include<algorithm> 7 #include<string.h> 8 #include<stdlib.h> 9 #include<vector> 10 #include<set> 11 #include<map> 12 #include<stack> 13 #include<string> 14 #include<queue> 15 16 #define repA(p,q,i) for( int (i)=(p); (i)!=(q); ++(i) ) 17 #define repAE(p,q,i) for( int (i)=(p); (i)<=(q); ++(i) ) 18 #define repD(p,q,i) for( int (i)=(p); (i)!=(q); --(i) ) 19 #define repDE(p,q,i) for( int (i)=(p); (i)>=(q); --(i) ) 20 21 double arr[1010]; 22 double res[1010]; 23 24 int LFarr[1010]; 25 int RGarr[1010]; 26 27 void INC(int n); 28 void DEC(int n); 29 30 int main() 31 { 32 int n; 33 while( scanf("%d", &n) != EOF ) 34 { 35 repA(0, n, i) 36 scanf("%lf", &arr[i]); 37 38 INC(n); 39 DEC(n); 40 int result = -0x3f3f3f3f; 41 repA(0, n, i) 42 result = max(result, LFarr[i]+RGarr[i]); 43 //printf("%d %d\n", LFarr[i], RGarr[i]); 44 45 printf("%d\n", n-result); 46 47 } 48 return 0; 49 } 50 51 void INC(int n) 52 { 53 int rd,lf, rg, mid; 54 rd = 0; res[0] = arr[0]; 55 56 repA(0, n, i) 57 { 58 if( arr[i] > res[rd] ) 59 { 60 res[++rd] = arr[i]; 61 LFarr[i] = rd+1; 62 } 63 64 else{ 65 lf = 0; rg = rd; 66 while(rg >= lf) 67 { 68 mid = (rg+lf)/2; 69 if(res[mid] == arr[i]) 70 { lf=mid; break; } 71 else if(res[mid] > arr[i]) 72 rg = mid-1; 73 else lf = mid+1; 74 } 75 res[lf] = arr[i]; 76 LFarr[i] = lf + 1; 77 } 78 79 } 80 81 return ; 82 } 83 84 85 void DEC(int n) 86 { 87 int rd,lf, rg, mid; 88 rd = 0; res[0] = arr[n-1]; 89 RGarr[n-1] = 0; 90 91 repDE(n-2, 0, i) 92 { 93 if( arr[i] > res[rd] ) 94 { 95 res[++rd] = arr[i]; 96 RGarr[i] = rd; 97 } 98 99 else{ 100 lf = 0; rg = rd; 101 while(rg >= lf) 102 { 103 mid = (rg+lf)/2; 104 if(res[mid] == arr[i]) 105 { lf=mid; break; } 106 else if(res[mid] > arr[i]) 107 rg = mid-1; 108 else lf = mid+1; 109 } 110 RGarr[i] = lf; 111 if(res[lf] == arr[i]) 112 ++RGarr[i]; 113 114 res[lf] = arr[i]; 115 } 116 } 117 118 return ; 119 }