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

本文介绍了一道关于塔的序列动态规划问题及其解决方案。问题要求在满足特定约束条件下选择塔集合以最大化目标函数。文章详细阐述了解题思路,利用数据结构进行优化,并给出具体实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

nn 座塔标号为 1n,每个塔有两种属性 rar,a,现在你要从这些塔中选取若干个塔,使得:对于任意两座塔 i,j (i<j)i,j (i<j),需满足 i+riji+ri≤j
求在所有满足上述条件的塔的选择集合 SS 中,求 max{iSairi}
数据范围:1rin106ai1091≤ri≤n≤106,ai≤109

考场上打挂了炸成10分。。
这题一看就是序列dp,不过要用数据结构优化。
题目给定的塔是按顺序的,所以对于一个塔是否能选,
我们只要考虑前面的塔攻击不到这个塔,以及这个塔攻击不到前面的塔就ok。
fifi 为只考虑前 ii 座塔,选入 i 这座塔的最优答案。
那么 fifi 就等于 [1iri][1,i−ri] 范围内无法攻击到 ii 塔中所有塔 f 的最大值,再加airiairi
然后我们用数据结构维护个前缀最大值,为了保证前面的塔打不到当前的塔,
只插入打不到它的。由于已经按位置排了序,所以前面打不到它的肯定打不到它后面的塔。所以插入后就可以一直放在那里了。复杂度 O(n log n)O(n log 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值