uva1471
阿新 • • 發佈:2018-03-03
ans ng- printf 解法 pac 最大 post track ios
這是LIS的變形,題意是求一個序列中去掉某個連續的序列後,能得到的最長連續遞增序列的長度。
用DP的解法是:吧這個序列用數組a來記錄,再分別用兩個數組f記錄以i結尾的最長連續遞增序列的長度,g[i]記錄以i開頭的最長連續遞增序列。
然後像求DP求LIS一樣遍歷整個序列求出i前面所有小於a[i]的元素中以該元素結尾的最長序列f[j], 那麽 dp[i] = g[j] + f[i],?這樣時間復雜度為O(n^2)。
因為和普通的LIS相似,所以能夠利用LIS的優化方法把該題的時間復雜的優化到O(nlogn)。方法仍是利用一個數組d[i]記錄長度為 i 的連續遞增序列的最後一個元素的最小值,顯然該序列是單調遞增的。所以上面紅色字體的操作能夠通過二分查找直接得到f[j]的值,進而得到一個可行的長度ans, 然後更新數組d就可以,更新的方法是假設以a[i]小於數組d中記錄的與a[i]長度同樣的序列的最後一個元素的值。那麽把這個值改為a[i], 即? d[f[i]] = min(a[i], d[f[i]]);? 終於ans的最大值即為答案。
代碼例如以下:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAXN = 200050; const int INF = 1 << 30; int a[MAXN], f[MAXN], g[MAXN], d[MAXN]; int main() { int t, n, i; scanf("%d", &t); while(t--) { scanf("%d", &n); for(i = 1; i <= n; i++) scanf("%d", &a[i]); f[1] = 1; for(i = 2; i <= n; i++) if(a[i] > a[i - 1]) f[i] = f[i - 1] + 1; else f[i] = 1; g[n] = 1; for(i = n - 1; i > 0; i--) if(a[i] < a[i + 1]) g[i] = g[i + 1] + 1; else g[i] = 1; int ans = 0; for(i = 0; i <= n; i++) d[i] = INF; //d[i]的值所有賦值為INF,方便二分查找和更新d[i] for(i = 1; i <= n; i++) { int len = (lower_bound(d + 1, d + 1 + i, a[i]) - (d + 1)) + g[i]; ans = max(len, ans); d[f[i]] = min(a[i], d[f[i]]); } printf("%d\n", ans); } return 0; }
uva1471