1. 程式人生 > >【NOIP訓練】塔防遊戲 序列DP / 資料結構

【NOIP訓練】塔防遊戲 序列DP / 資料結構

n 座塔標號為 1n,每個塔有兩種屬性 ra,現在你要從這些塔中選取若干個塔,使得:對於任意兩座塔 i,j(i<j),需滿足 i+rij
求在所有滿足上述條件的塔的選擇集合 S 中,求 max{iSairi}
資料範圍:1rin106ai109

考場上打掛了炸成10分。。
這題一看就是序列dp,不過要用資料結構優化。
題目給定的塔是按順序的,所以對於一個塔是否能選,
我們只要考慮前面的塔攻擊不到這個塔,以及這個塔攻擊不到前面的塔就ok。

fi 為只考慮前 i 座塔,選入 i 這座塔的最優答案。
那麼 fi 就等於 [1iri] 範圍內無法攻擊到 i 塔中所有塔 f 的最大值,再加airi
然後我們用資料結構維護個字首最大值,為了保證前面的塔打不到當前的塔,
只插入打不到它的。由於已經按位置排了序,所以前面打不到它的肯定打不到它後面的塔。所以插入後就可以一直放在那裡了。複雜度 O(nlogn)
程式碼:

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