hdu4604 不错的子序列问题
? ? ? 給你一個棧,里面有n個數,和一個雙頭隊列(空的),每次從棧里拿出一個數據,有三種選擇,可以選擇丟棄這個數字,也可以放到隊頭或者隊尾,最后問你這個隊列你面的最長連續非下降序列的長度...
思路:
? ? ? 我感覺就是在1025的基礎上加強了幾個等級,那個題目就是二分貪心求公共子序列,這個題目的細節是用到了1025的思路的,首先我們枚舉每一個數,把他當做進隊列的第一個數字,那么此時的答案就是?該起點開始的最長費遞減子序列 + 該起點開始的最長非遞增子序列 - 他們相同的部分.他們相同的部分是的數字肯定是 當前這個數字,那么我們只要找到他倆序列中含有的當前這個數的個數中較小的哪一個減去就行了(相同部分一定是小的是大的子集).值得注意的是我們要倒著枚舉數據,減少時間復雜度..
如果沒看懂的話我就幫忙回一下1025,正好自己也總結下,dp是自己的弱點,有必要總結..1025 說的是給你n個數(n很大) 求上升子序列...那個題目的思想是 二分 + 貪心(個人感覺?,有的人認為是 二分 + dp, 隨意,dp和貪心相同又不同)開一個數組now[i],記錄的是第i個位置最小可以是now[i],對于每一個數num[i]每次我們二分找到num[i],在now[i]中的位置,也就是i,如果這個i>當前長度,那么就更新當前長度,其實這個[i]就是以當前這個數為序列終點的序列的長度,4046上面的那個題目用到的就是在now[i]中再次二分找到now[i]的起始位置,更新的時候我們找的是終止位置,根據這個差我們就找到了重復的num[i]的個數,值得注意一點的就是當前的這個now數組中的數并不是什么子序列的數字,只是單純的記錄某個位置的最小,沒有別的意義,光靠這個數組無法輸出真正的子序列,但是對于當前時刻當前的num[i],now[i]中連續的num[i]的個數是num[i]為終點的子序列的最后幾位數,還有沒被別的更新,所以根據now[]中連續的num[i]我們算出的連續num[i].的個數是正確的...
#include<stdio.h> #include<string.h>#define N 100000 + 500 int upp[N] ,loww[N] ,now[N]; int num[N]; int same[N];int minn(int x ,int y) {return x < y ? x : y; }int main () {int t ,n ,i;scanf("%d" ,&t);while(t--){scanf("%d" ,&n);for(i = 1 ;i <= n ;i ++)scanf("%d" ,&num[i]);int low ,up ,mid ,len;now[1] = num[n] ,len = 1;same[n] = 1;for(i = n - 1 ;i >= 1 ;i --){low = 1 ,up = len;int mk = 0;while(low <= up){mid = (low + up) >> 1;if(num[i] <= now[mid]) {low = mid + 1;mk = mid;}else up = mid - 1;}mk ++;if(mk > len) len ++;now[mk] = num[i];loww[i] = mk;low = 1 ,up = len;mk = 0;while(low <= up){mid = (low + up) >> 1;if(num[i] < now[mid]){low = mid + 1;mk = mid;}else up = mid - 1;}same[i] = loww[i] - mk;}now[1] = num[n];len = 1;for(i = n - 1 ;i >= 1 ;i --){low = 1 ,up = len;int mk = 0;while(low <= up){mid = (low + up) >> 1;if(num[i] >= now[mid]){low = mid + 1;mk = mid;}else up = mid - 1;}mk++;if(mk > len) len ++;now[mk] = num[i];upp[i] = mk; low = 1 ,up = len;mk = 0;while(low <= up){mid = (low + up) >> 1;if(num[i] > now[mid]){low = mid + 1;mk = mid;}else up = mid - 1;}same[i] = minn(same[i] ,upp[i] - mk);}int ans = 0;for(i = 1 ;i <= n ;i ++)if(ans < loww[i] + upp[i] - same[i])ans = loww[i] + upp[i] - same[i];printf("%d\n" ,ans);}return 0; }
總結
以上是生活随笔為你收集整理的hdu4604 不错的子序列问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hdu4450 不错的贪心
- 下一篇: hdu4561 连续最大积