题目:
道路旁一共有
n
n
n个可以建造防御塔的位置,从道路的起点到终点编号
1
−
n
1-n
1−n,相邻两个位置的距离为
1
1
1 。
防御塔有两种属性:攻击范围和攻击力。 定义一个防御塔的攻击效应为其攻击范围和攻击力的积。 已知可以在第 个位置建造的塔的攻击范围是
r
[
i
]
r[i]
r[i],攻击力是
a
[
i
]
a[i]
a[i]。 这个游戏很特殊,防御塔可以攻击别的防御塔,只要有别的防御塔在它的攻击范围内。
形式化地,如果第
i
i
i 个位置的防御塔的攻击范围是
r
i
r_i
ri ,那么它可以攻击第
j
j
j个位置的防御塔,当且仅当
j
j
j 满足
i
−
r
i
<
j
<
i
+
r
i
i-r_i<j<i+r_i
i−ri<j<i+ri。
塔之间不能互相攻击,最大化攻击效应的和。
n
≤
1
0
6
n\le 10^6
n≤106
solution:
数据范围小点就是个很水的
d
p
dp
dp
g
[
i
]
=
m
a
x
{
g
[
j
]
}
+
a
[
i
]
×
r
[
i
]
i
f
(
i
−
r
i
>
=
j
&
&
j
+
r
j
<
=
i
)
g[i]=max\{g[j]\}+a[i]\times r[i] \ \ if(i-r_i>=j\&\&j+r_j<=i)
g[i]=max{g[j]}+a[i]×r[i] if(i−ri>=j&&j+rj<=i)
数据范围大了就可以用数据结构优化
d
p
dp
dp
很明显要求前缀最大值可以用树状数组,但树状数组只能约束一个条件,某帅想的是
c
d
q
cdq
cdq分治但很不可做,其实只要用优先队列先把每个到过的点压进去,到了不会攻击到的地方再加进树状数组里
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define maxn 1000005
#define prit pair<int,int>
#define int long long
using namespace std;
int n,r[maxn],a[maxn],f[maxn],g[maxn],ans;
priority_queue< prit,vector<prit>,greater<prit> > q;
inline int rd(){
int x=0,f=1;char c=' ';
while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
return x*f;
}
inline int max(int x,int y){return x>y?x:y;}
inline void add(int x,int y){
for(;x<=n;x+=x&-x) f[x]=max(f[x],y);
}
inline int query(int x){
int sum=0;
for(;x;x-=x&-x) sum=max(sum,f[x]);
return sum;
}
signed main(){
freopen("td.in","r",stdin);
freopen("td.out","w",stdout);
n=rd();
for(int i=1;i<=n;i++) r[i]=rd();
for(int i=1;i<=n;i++) a[i]=rd();
for(int i=1;i<=n;i++){
while(!q.empty()){
int x=q.top().second;
if(q.top().first<=i) add(x,g[x]),q.pop();
else break;
}
g[i]=query(max(0,i-r[i]))+r[i]*a[i];
q.push(make_pair(i+r[i],i)); ans=max(ans,g[i]);
}
printf("%lld\n",ans);
return 0;
}