fjwc2019 D1T1 全連(dp+樹狀數組)

#178. 「2019冬令營提升組」全連數組

顯然咱們能夠得出一個$O(n^2)$的dp方程函數

記$f(i)$爲取到第$i$個音符時的最大分數,枚舉下一個音符的位置$j$進行轉移。spa

藍後咱們就能夠用樹狀數組存下$f(i)$的最大值,每次用$logn$的複雜度每次詢問$j=1 \rightarrow i-t[i]$中最大$f(j)$值。code

醬紫複雜度就變成了$O(nlogn)$blog

對於$f(i)$在位置$i+t[i]$以後才能做爲轉移的一個選擇的問題,咱們能夠打一個延遲標記(ping函數),用相似鏈式前向星的結構存儲(就像存邊同樣)。get

每次到達一個$k$,就把每一個從$k$開始起轉移做用的$f(i)加入樹狀數組。io

#include<cstdio> typedef long long ll; ll max(ll a,ll b){return a>b?a:b;} void read(ll &x){ char c=getchar();x=0; while(c<'0'||c>'9') c=getchar(); while('0'<=c&&c<='9') x=x*10+(c^48),c=getchar(); } #define N 1000005 ll s[N],a[N],t[N],f[N],ans; int n,cnt,hd[N],nxt[N],ed[N],poi[N]; void add(int x,ll v){for(;x<=n;x+=x&-x)s[x]=max(s[x],v);} ll ask(int x){ll re=0;for(;x;x-=x&-x)re=max(re,s[x]);return re;} void ping(int x,int y){ nxt[ed[x]]=++cnt; hd[x]=hd[x]?hd[x]:cnt; ed[x]=cnt; poi[cnt]=y; } int main(){ freopen("fc.in","r",stdin); freopen("fc.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;++i) read(t[i]); for(int i=1;i<=n;++i) read(a[i]); for(int i=1;i<=n;++i){ for(int j=hd[i];j;j=nxt[j]) add(poi[j],f[poi[j]]);//f[poi[j]]從i開始能夠做爲一個選擇,加入樹狀數組 f[i]=a[i]*t[i]; if(i>t[i]) f[i]+=ask(i-t[i]);//查詢1~i-t[i]的最優選擇 if(i+t[i]<=n) ping(i+t[i],i);//把f(i)加入位置i+t[i]的標記中 ans=max(ans,f[i]); }printf("%lld",ans); return 0; }
相關文章
相關標籤/搜索