51nod 1218 最長遞增子序列 V2(dp + 思維)
阿新 • • 發佈:2017-07-04
ear www str tdi binsearch tor con bsp href
題目鏈接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1218
題解:先要確定這些點是不是屬於最長遞增序列然後再確定這些數在最長遞增序列中出現的次數,如果大於1次顯然是可能出現只出現1次肯定是必然出現。那麽就是怎麽判斷是不是屬於最長遞增序列,這個只要順著求一下最長遞增標一下該點屬於長度幾然後再逆著求一下最長遞減標一下該點屬於長度幾如果兩個下標之和等於最長長度+1那麽該點就屬於最長遞增序列,然後就是求1~len(len表示最長的長度)中各個長度出現的次數就行。
#include <iostream> #include <cstring> #include <cstdio> #include <vector> #define inf 0X3f3f3f3f using namespace std; const int M = 5e4 + 10; int a[M] , b[M] , dpa[M] , dpb[M] , vis[M]; bool vs[M]; int binsearch(int l , int r , int num) { int mid = (l + r) >> 1; int ans = 0; while(l <= r) { mid = (l + r) >> 1; if(b[mid] > num) r = mid - 1; else { ans = mid; l = mid + 1; } } return ans; } int binsearch2(int l , int r , int num) { int mid = (l + r) >> 1; int ans = 0; while(l <= r) { mid = (l + r) >> 1; if(b[mid] < num) r = mid - 1; else { ans = mid; l = mid + 1; } } return ans; } int main() { int n; scanf("%d" , &n); for(int i = 1 ; i <= n ; i++) scanf("%d" , &a[i]); int len = 0; b[0] = -1; for(int i = 1 ; i <= n ; i++) { if(a[i] > b[len]) { len++; b[len] = a[i]; dpa[i] = len; continue; } else { int pos = binsearch(1 , len , a[i]); b[pos + 1] = min(b[pos + 1] , a[i]); dpa[i] = pos + 1; } } int len2 = 0; memset(b , inf , sizeof(b)); for(int i = n ; i >= 1 ; i--) { if(a[i] < b[len2]) { len2++; b[len2] = a[i]; dpb[i] = len2; } else { int pos = binsearch2(1 , len2 , a[i]); b[pos + 1] = max(b[pos + 1] , a[i]); dpb[i] = pos + 1; } } memset(vs , false , sizeof(vs)); for(int i = 1 ; i <= n ; i++) { if(dpa[i] + dpb[i] == len + 1) { vis[dpa[i]]++; vs[i] = true; } } printf("A:"); for(int i = 1 ; i <= n ; i++) { if(vis[dpa[i]] > 1 && vs[i]) printf("%d " , i); } printf("\n"); printf("B:"); for(int i = 1 ; i <= n ; i++) { if(vis[dpa[i]] == 1 && vs[i]) printf("%d " , i); } printf("\n"); return 0; }
51nod 1218 最長遞增子序列 V2(dp + 思維)