1. 程式人生 > >YYH的蒼天大竹(NOIP模擬賽Round 6)

YYH的蒼天大竹(NOIP模擬賽Round 6)

線段樹 include tps max add 一段 fin problem tree

原題傳送門

這道題我們很顯然要用DP來做。

那麽首先我們需要構造出一個DP方程

f[i]肯定由另一個狀態dp轉移後+1得到,那麽這個狀態是什麽呢?

很明顯就是mint[i]~i-k(在此mint表示的是以i為結尾的竹子最左端最多能延展到的位置)

看到這個之後我們想到了一個N^2DP

但是還是不夠

我們想一想如何得到mint?

mint就是判斷一段區間的最大值減去最小值是否滿足題意

那麽我們可不可以用數據結構得出這個答案呢?

顯然我們可以用線段樹來優化這個過程

時間復雜度O(nlogn)

同樣在得出答案的過程我們也可以用線段樹加速

下面貼代碼

#include<cstdio>
#include
<cstring> #define inf 0x3f3f3f3f #define min(x,y) (x<y?x:y) #define max(x,y) (x>y?x:y) using namespace std; int a[100005]; struct mm{ int v1,v2; }t[300005]; int mint[100005]; int f[300005]; int m=1,n,s,l; void pushdown(int i){t[i].v1=min(t[i<<1].v1,t[i<<1|1].v1);t[i].v2=max(t[i<<1].v2,t[i<<1
|1].v2);} void buildtree(){ while(m<n+2)m<<=1; for(int i=1;i<=n;i++) t[i+m].v1=t[i+m].v2=a[i]; for(int i=m-1;i;i--) pushdown(i); } int query(int l,int r) { int maxn=-inf,minn=inf; for(l=l+m-1,r=r+m+1;l^r^1;l>>=1,r>>=1) { if(~l&1)minn=min(minn,t[l^1
].v1),maxn=max(maxn,t[l^1].v2); if(r&1)minn=min(minn,t[r^1].v1),maxn=max(maxn,t[r^1].v2); } return maxn-minn; } int que(int l,int r) { int minn=inf; for(l+=m-1,r+=m+1;l^r^1;l>>=1,r>>=1) { if(~l&1)minn=min(minn,f[l^1]); if(r&1)minn=min(minn,f[r^1]); } return minn; } void push(int x){f[x]=min(f[x<<1],f[x<<1|1]);} void add(int x,int y){for(f[x+=m]=y,x>>=1;x;x>>=1)push(x);} int main(){ memset(f,127/3,sizeof(f)); scanf("%d%d%d",&n,&s,&l);n++; for(int i=2;i<=n;i++)scanf("%d",&a[i]); a[1]=a[2]; buildtree(); int le=1; for(int i=1;i<=n;i++) { int tmp=query(le,i); while(tmp>s) { tmp=query(++le,i); } mint[i]=le; } add(1,0); for(int i=2;i<=n;i++) if(max(1,mint[i]-1)>i-l)add(i,inf); else add(i,que(max(1,mint[i]-1),i-l)+1); printf("%d\n",f[n+m]>=inf?-1:f[n+m]); return 0; }

YYH的蒼天大竹(NOIP模擬賽Round 6)