1. 程式人生 > >【NOIP2013】花匠

【NOIP2013】花匠

oid log 兩個 條件 amp stdio.h 思考 max ret

Description

花匠棟棟種了一排花,每株花都有自己的高度。花兒越長越大,也越來越擠。棟棟決定把這排中的一部分花移走,將剩下的留在原地,使得剩下的花能有空間長大,同時,棟棟希望剩下的花排列得比較別致。
具體而言,棟棟的花的高度可以看成一列整數h1, h2, … , hn。設當一部分花被移走後,剩下的花的高度依次為g1, g2, … , gm,則棟棟希望下面兩個條件中至少有一個滿足:
條件 A:對於所有的1 ≤ i < m / 2,g_2i > g_2i?1,且g_2i > g_2i+1;
條件 B:對於所有的1 ≤ i < m / 2,g_2i < g_2i?1,且g_2i < g_2i+1。
此處2i及2i-1,2i+1都為下標。
註意上面兩個條件在m = 1時同時滿足,當m > 1時最多有一個能滿足。
請問,棟棟最多能將多少株花留在原地。

Input

輸入的第一行包含一個整數 n,表示開始時花的株數。
第二行包含 n 個整數,依次為h1, h2,… , hn,表示每株花的高度。

Output

輸出一行,包含一個整數 m,表示最多能留在原地的花的株數。

Sample Input

5
5 3 2 1 2

Sample Output

3

Hint

對於 20%的數據,n ≤ 10;
對於 30%的數據,n ≤ 25;
對於 70%的數據,n ≤ 1000,0 ≤ hi ≤ 1000;
對於 100%的數據,1 ≤ n ≤ 100,000,0 ≤ hi ≤ 1,000,000,所有的h_i隨機生成,所有隨機數服從某區間內的均勻分布。

題解: 推薦做這道題之前先學會LST的nlogn做法,好了,對於這道題我設了一個狀態dp[i][0]表示以a[i]結尾的最長滿足條件A的序列長度,dp[i][1]就是以a[i]結尾滿足條件b的最長長度,很明顯我們可以n平方求出dp[1~n],然後取個max就可以了,轉移情況討論就行了,比如dp[i][0]從前面的dp[j][0]的長度為基數,並且a[j]<a[i]轉移,加個1取max,分四種情況就可以了,剩下的自己思考一下。優化就用兩顆線段樹,分別維護dp[i][0~1]為基數,偶數的情況就nlogn求出來了。 代碼:
#include<iostream>
#include
<stdio.h> #include<stdlib.h> #include<algorithm> #include<cstring> #define inf (1<<30) const int MAXN=100100; using namespace std; int dp[MAXN][2],a[MAXN],n,ans=0,shang=0,xvv=0; struct tree{ int l,r,max; }b[1000010*4][2]; void cl(){ memset(dp,0,sizeof(dp)); memset(a,0,sizeof(a)); } void build(int xv,int l,int r){ xvv=max(xvv,xv); if(l==r){ b[xv][0].l=l,b[xv][0].r=r,b[xv][0].max=0; b[xv][1].l=l,b[xv][1].r=r,b[xv][1].max=0; return; } b[xv][0].l=l,b[xv][0].r=r,b[xv][0].max=0; b[xv][1].l=l,b[xv][1].r=r,b[xv][1].max=0; int mid=(l+r)/2; build(xv*2,l,mid); build(xv*2+1,mid+1,r); } void insert(int xv,int aum,int zhi,int x){ int l=b[xv][x].l,r=b[xv][x].r,mid=(l+r)/2; if(l==r&&r==aum){ b[xv][x].max=zhi; return; } if(aum<=mid) insert(xv*2,aum,zhi,x); else insert(xv*2+1,aum,zhi,x); b[xv][x].max=max(b[xv*2][x].max,b[xv*2+1][x].max); } int query(int xv,int l,int r,int x){ int L=b[xv][x].l,R=b[xv][x].r,mid=(L+R)/2; if(L==l&&R==r) return b[xv][x].max; if(r<=mid) return query(xv*2,l,r,x); else if(l>mid) return query(xv*2+1,l,r,x); else return max(query(xv*2,l,mid,x),query(xv*2+1,mid+1,r,x)); } void DP(){ dp[1][0]=dp[1][1]=1; insert(1,a[1],dp[1][0],1); for(int i=1;i<=n;i++){ if(a[i]!=0){ int x=query(1,0,a[i]-1,1); dp[i][0]=max(dp[i][0],x+1); } int xx=query(1,a[i]+1,shang,0); dp[i][0]=max(dp[i][0],xx+1); if(dp[i][0]%2==0) insert(1,a[i],dp[i][0],0); else insert(1,a[i],dp[i][0],1); } for(int i=1;i<xvv;i++) b[i][0].max=0,b[i][1].max=0; insert(1,a[1],dp[1][1],1); for(int i=1;i<=n;i++){ int x=query(1,a[i]+1,shang,1); dp[i][1]=max(dp[i][1],x+1); if(a[i]!=0){ int xx=query(1,0,a[i]-1,0); dp[i][1]=max(dp[i][1],xx+1); } if(dp[i][1]%2==0) insert(1,a[i],dp[i][1],0); else insert(1,a[i],dp[i][1],1); } } int main(){ cl(); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]),shang=max(shang,a[i]); shang++; build(1,0,shang); DP(); for(int i=1;i<=n;i++) ans=max(ans,dp[i][0]); for(int i=1;i<=n;i++) ans=max(ans,dp[i][1]); printf("%d",ans); }

【NOIP2013】花匠