【NOIP训练】塔防游戏 序列DP / 数据结构

版权声明:All rights reserved. https://blog.csdn.net/qq_42814118/article/details/82667339

n 座塔标号为 1 n ,每个塔有两种属性 r a ,现在你要从这些塔中选取若干个塔,使得:对于任意两座塔 i , j   ( i < j ) ,需满足 i + r i j
求在所有满足上述条件的塔的选择集合 S 中,求 m a x { i S a i r i }
数据范围: 1 r i n 10 6 a i 10 9

考场上打挂了炸成10分。。
这题一看就是序列dp,不过要用数据结构优化。
题目给定的塔是按顺序的,所以对于一个塔是否能选,
我们只要考虑前面的塔攻击不到这个塔,以及这个塔攻击不到前面的塔就ok。
f i 为只考虑前 i 座塔,选入 i 这座塔的最优答案。
那么 f i 就等于 [ 1 i r i ] 范围内无法攻击到 i 塔中所有塔 f 的最大值,再加 a i r i
然后我们用数据结构维护个前缀最大值,为了保证前面的塔打不到当前的塔,
只插入打不到它的。由于已经按位置排了序,所以前面打不到它的肯定打不到它后面的塔。所以插入后就可以一直放在那里了。复杂度 O ( n   l o g   n )
代码:

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

猜你喜欢

转载自blog.csdn.net/qq_42814118/article/details/82667339