码迷,mamicode.com
首页 > 编程语言 > 详细

fjwc2019 D1T1 (dp+树状数组)

时间:2019-02-24 17:24:10      阅读:182      评论:0      收藏:0      [点我收藏+]

标签:函数   return   ++   type   amp   fine   define   前向星   tchar   

#178. 「2019冬令营提高组」全连

显然我们可以得出一个$O(n^2)$的dp方程

记$f(i)$为取到第$i$个音符时的最大分数,枚举下一个音符的位置$j$进行转移。

蓝后我们就可以用树状数组存下$f(i)$的最大值,每次用$logn$的复杂度每次询问$j=1 \rightarrow i-t[i]$中最大$f(j)$值。

酱紫复杂度就变成了$O(nlogn)$

对于$f(i)$在位置$i+t[i]$之后才能作为转移的一个选择的问题,我们可以打一个延迟标记(ping函数),用类似链式前向星的结构存储(就像存边一样)。

每次到达一个$k$,就把每个从$k$开始起转移作用的$f(i)加入树状数组。

#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;
}

 

fjwc2019 D1T1 (dp+树状数组)

标签:函数   return   ++   type   amp   fine   define   前向星   tchar   

原文地址:https://www.cnblogs.com/kafuuchino/p/10426896.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!