【NOIP訓練】塔防遊戲 序列DP / 資料結構
阿新 • • 發佈:2018-12-09
題
有 座塔標號為 ,每個塔有兩種屬性 ,現在你要從這些塔中選取若干個塔,使得:對於任意兩座塔 ,需滿足 。
求在所有滿足上述條件的塔的選擇集合 中,求 。
資料範圍:。
解
考場上打掛了炸成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;
}