$[SCOI2014]$方伯伯的玉米田

性感伯伯,在線拔苗,快來幫忙,一同快樂c++

若是我說我是找標籤看到這題來練樹狀數組的你信嗎?git

好一道毒瘤的\(DP\)數組

感性理解一下一個結論,咱們每次拔苗右端點必定是最右邊的玉米。fetch

證實在這篇題解中已經講得很清楚了對吧。優化

我主要是講一下有關\(DP\)方程的事兒。spa

一個顯然的狀態是\(f[i][j]\)表示咱們已經處理了前\(i\)個玉米苗,並對第\(i\)個玉米苗拔高了\(j\)次的答案。code

方程是\(f[i][j]=max\{f[k][l]\}+1(1\leq k<i,0\leq l\leq j,H[i]+j\geq H[k]+l)\)blog

顯然這個轉移會\(TLE\),因而咱們考慮優化,找二維前綴\(max\),用二維樹狀數組實現。get

等。。等一下,\(H[i]+j\geq H[k]+l?\),這個限制用樹狀數組顯然是難以知足的。it

那麼咱們不妨考慮將高度的限制加入狀態。

即設\(f[i][j][k]\)表示前\(i\)個玉米苗,以不超過\(j\)高度且被操做了不超過\(k\)次的玉米苗結尾。

限制中就少了高度的限制。而後在用相似揹包的思想滾掉\(i\)這一維便可。

#include<bits/stdc++.h>
using namespace std;
#define int long long
namespace AE86
{
    const int bufl=1<<15;
    char buf[bufl],*s=buf,*t=buf;
    inline int fetch()
    {
        if(s==t){t=(s=buf)+fread(buf,1,bufl,stdin);if(s==t)return EOF;}
        return*s++;
    }
    inline int read()
    {
        int a=0,b=1,c=fetch();
        while(!isdigit(c)) b^=c=='-',c=fetch();
        while(isdigit(c)) a=a*10+c-48,c=fetch();
        return b?a:-a;
    }
}
const int N=1e4+10;
const int K=5e2+10;
int n,k,Ans,Max,H[N],f[N][K],Tar[N][K];

inline void Insert(int x,int y,int Val)
{
    for(;x<=Max+k;x+=x&-x)
        for(int j=y;j<=k+1;j+=j&-j)
            Tar[x][j]=max(Tar[x][j],Val);
}
inline int Ask(int x,int y)
{
    int Sum=0;
    for(;x;x-=x&-x)
        for(int j=y;j;j-=j&-j)
            Sum=max(Sum,Tar[x][j]);
    return Sum;
}
signed main(){
#ifndef ONLINE_JUDGE
    freopen("A.in","r",stdin);
#endif
    n=AE86::read(),k=AE86::read();
    for(int i=1;i<=n;i++) H[i]=AE86::read(),Max=max(Max,H[i]);
    for(int i=1;i<=n;i++)
        for(int j=k;j>=0;j--)
            f[i][j]=Ask(H[i]+j,j+1)+1,Insert(H[i]+j,j+1,f[i][j]);
    for(int i=1;i<=n;i++)
        for(int j=k;j>=0;j--)
            Ans=max(Ans,f[i][j]);
    printf("%lld\n",Ans);
}
相關文章
相關標籤/搜索