啊今天爆零啦!
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;
}
后两题比较神仙,先算了吧。