23th.Feb.2019

啊今天爆零啦!

QAQ,多写一句废话就爆零了Dp好狠毒啊。

还是来分析题目吧。

  • 假如当前到了i,哪些j可以传递给i?
    • j+t[j]<=i;
    • j<=i-t[i]。
  • 不错,就是这样两个条件,你只要解决了就可以很快写掉它。
  • 假如只有第二个条件,显然我们写一个树状数组维护一个前缀最大值就可以解决。可是第一个条件限制了我们不能直接查询,因为还要保证你查找的j+t[j]<=i,咋办啊。
  • 一种好的办法就是把每个点的状态插入堆里面,每次到了i,我们把j+t[j]<=i的点插入树状数组并从堆里删除,那么此时查1~i-t[i]区间的最值就是合法的了。简单吧。
  • 代码也特别简单,前提是别瞎写,比如我这个sb就爆零了。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e6+10;
ll n,t[N],a[N],ans,h[N],f[N];
priority_queue<pair<ll,ll > >q;
inline ll read(){
    char ch=getchar();int num=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){num=(num<<1)+(num<<3)+(ch^48);ch=getchar();}
    return num*f;
}
void update(ll x,ll val){
    for(;x<=n;x+=x&(-x)) h[x]=max(h[x],val);
}
ll query(ll x){
    ll res=0;
    for(;x>0;x-=x&(-x)) res=max(res,h[x]);
    return res;
}
int main(){
    freopen("fc.in","r",stdin);
    freopen("fc.out","w",stdout);
    n=read();
    for(int i=1;i<=n;++i){
        t[i]=read();
    }
    for(int i=1;i<=n;++i){
        a[i]=read();a[i]*=t[i];
    }
    for(int i=1;i<=n;++i){
        while(q.size()&&(-q.top().first)<=i){
            ll x=q.top().second;
            q.pop();
            update(x,f[x]);
        }
        ll val;
        //if(i-t[i]>=0) 就是这句话导致了爆零
        f[i]=max(0LL,query(i-t[i])+a[i]);ans=max(ans,f[i]);
        q.push(make_pair(-(i+t[i]),i));
    }
    printf("%lld\n",ans);
    return 0;
}

后两题比较神仙,先算了吧。

猜你喜欢

转载自www.cnblogs.com/kgxw0430/p/10422875.html