版权声明:All rights reserved. https://blog.csdn.net/qq_42814118/article/details/82667339
题
有
座塔标号为
,每个塔有两种属性
,现在你要从这些塔中选取若干个塔,使得:对于任意两座塔
,需满足
。
求在所有满足上述条件的塔的选择集合
中,求
。
数据范围:
。
解
考场上打挂了炸成10分。。
这题一看就是序列dp,不过要用数据结构优化。
题目给定的塔是按顺序的,所以对于一个塔是否能选,
我们只要考虑前面的塔攻击不到这个塔,以及这个塔攻击不到前面的塔就ok。
记
为只考虑前
座塔,选入
这座塔的最优答案。
那么
就等于
范围内无法攻击到
塔中所有塔
的最大值,再加
。
然后我们用数据结构维护个前缀最大值,为了保证前面的塔打不到当前的塔,
只插入打不到它的。由于已经按位置排了序,所以前面打不到它的肯定打不到它后面的塔。所以插入后就可以一直放在那里了。复杂度
。
代码:
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define R register
#define Maxn 2000005
#define LL long long
struct tower
{
LL atk,r;
}t[Maxn];
int n;
LL f[Maxn],ans;
inline int lowbit(R int x){return x&-x;}
struct BIT
{
LL tree[Maxn];
LL query(R int pos1)
{
R LL ret=0ll;
for (;pos1;pos1-=lowbit(pos1)) ret=max(ret,tree[pos1]);
return ret;
}
void insert(R int pos1,R LL val)
{
for (;pos1<=n;pos1+=lowbit(pos1)) tree[pos1]=max(tree[pos1],val);
}
}A;
int first[Maxn],next[Maxn],to[Maxn],cnt;
void link(R int x,R int y)
{
next[++cnt] = first[x]; first[x] = cnt; to[cnt] = y;
}
int main()
{
// freopen("td5.in","r",stdin);
scanf("%d",&n);
for (R int i=1;i<=n;++i) scanf("%lld",&t[i].r);
for (R int i=1;i<=n;++i) scanf("%lld",&t[i].atk);
for (R int i=1;i<=n;++i)
{
for (R int j=first[i];j;j=next[j]) A.insert(to[j],f[to[j]]);
f[i]=max(f[i],A.query(max(i-t[i].r,0ll)))+t[i].atk*t[i].r;
link(i+t[i].r,i);
ans=max(ans,f[i]);
}
printf("%lld\n",ans);
return 0;
}