hdu4604 不错的子序列问题
? ? ? 給你一個(gè)棧,里面有n個(gè)數(shù),和一個(gè)雙頭隊(duì)列(空的),每次從棧里拿出一個(gè)數(shù)據(jù),有三種選擇,可以選擇丟棄這個(gè)數(shù)字,也可以放到隊(duì)頭或者隊(duì)尾,最后問(wèn)你這個(gè)隊(duì)列你面的最長(zhǎng)連續(xù)非下降序列的長(zhǎng)度...
思路:
? ? ? 我感覺(jué)就是在1025的基礎(chǔ)上加強(qiáng)了幾個(gè)等級(jí),那個(gè)題目就是二分貪心求公共子序列,這個(gè)題目的細(xì)節(jié)是用到了1025的思路的,首先我們枚舉每一個(gè)數(shù),把他當(dāng)做進(jìn)隊(duì)列的第一個(gè)數(shù)字,那么此時(shí)的答案就是?該起點(diǎn)開(kāi)始的最長(zhǎng)費(fèi)遞減子序列 + 該起點(diǎn)開(kāi)始的最長(zhǎng)非遞增子序列 - 他們相同的部分.他們相同的部分是的數(shù)字肯定是 當(dāng)前這個(gè)數(shù)字,那么我們只要找到他倆序列中含有的當(dāng)前這個(gè)數(shù)的個(gè)數(shù)中較小的哪一個(gè)減去就行了(相同部分一定是小的是大的子集).值得注意的是我們要倒著枚舉數(shù)據(jù),減少時(shí)間復(fù)雜度..
如果沒(méi)看懂的話(huà)我就幫忙回一下1025,正好自己也總結(jié)下,dp是自己的弱點(diǎn),有必要總結(jié)..1025 說(shuō)的是給你n個(gè)數(shù)(n很大) 求上升子序列...那個(gè)題目的思想是 二分 + 貪心(個(gè)人感覺(jué)?,有的人認(rèn)為是 二分 + dp, 隨意,dp和貪心相同又不同)開(kāi)一個(gè)數(shù)組now[i],記錄的是第i個(gè)位置最小可以是now[i],對(duì)于每一個(gè)數(shù)num[i]每次我們二分找到num[i],在now[i]中的位置,也就是i,如果這個(gè)i>當(dāng)前長(zhǎng)度,那么就更新當(dāng)前長(zhǎng)度,其實(shí)這個(gè)[i]就是以當(dāng)前這個(gè)數(shù)為序列終點(diǎn)的序列的長(zhǎng)度,4046上面的那個(gè)題目用到的就是在now[i]中再次二分找到now[i]的起始位置,更新的時(shí)候我們找的是終止位置,根據(jù)這個(gè)差我們就找到了重復(fù)的num[i]的個(gè)數(shù),值得注意一點(diǎn)的就是當(dāng)前的這個(gè)now數(shù)組中的數(shù)并不是什么子序列的數(shù)字,只是單純的記錄某個(gè)位置的最小,沒(méi)有別的意義,光靠這個(gè)數(shù)組無(wú)法輸出真正的子序列,但是對(duì)于當(dāng)前時(shí)刻當(dāng)前的num[i],now[i]中連續(xù)的num[i]的個(gè)數(shù)是num[i]為終點(diǎn)的子序列的最后幾位數(shù),還有沒(méi)被別的更新,所以根據(jù)now[]中連續(xù)的num[i]我們算出的連續(xù)num[i].的個(gè)數(shù)是正確的...
#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; }
總結(jié)
以上是生活随笔為你收集整理的hdu4604 不错的子序列问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: hdu4450 不错的贪心
- 下一篇: hdu4561 连续最大积