题意
注意收到的伤害值写的有点问题,实际上是
a
2
+
∑
j
=
1
k
(
A
i
,
j
−
C
j
)
2
\sqrt{a^2+\sum_{j=1}^k(A_{i,j}-C_j)^2}
a2+∑j=1k(Ai,j−Cj)2,没有后面的-a
数据范围
时限6S
解法
首先由于题目中的限制“选了第i个敌人就再也不能和1到i-1的敌人作战”,我们可以观察后得出dp:
a
n
s
[
i
]
=
m
i
n
(
a
n
s
[
u
]
+
∑
j
=
1
k
(
A
i
,
j
−
A
u
,
j
)
2
)
ans[i]=min(\sqrt{ans[u]+\sum_{j=1}^k(A_{i,j}-A_{u,j})^2})
ans[i]=min(ans[u]+∑j=1k(Ai,j−Au,j)2)
这是
O
(
N
2
)
O(N^2)
O(N2)的,可以通过20pts.
然后考虑k=1时的情况:我们发现其实ans[i]的值和u没有什么关系,而是和
A
u
,
1
A_{u,1}
Au,1有关,所以考虑设一个新数组alfa,其中alfa[i]表示
A
u
,
1
=
=
i
A_{u,1}==i
Au,1==i时,ans[u]最小是多少,然后对于第3个测试点,直接暴力维护alfa就可以通过了。
考虑4-5测试点,我们希望能快速维护类似alfa的东西:考虑beta数组,其中beta[j]表示当前
A
i
,
1
=
=
j
A_{i,1}==j
Ai,1==j的答案,那么每次计算出一个ans[i],都可以更新一些beta的值,然后我们发现由于
A
A
A数组的随机性,可以用线段树剪枝。每个位置维护所管辖区间的beta的最小值,然后修改时剪枝,具体看代码。
最后的50pts,因为多了一维,不能直接维护所有的beta了,所以我们转回去,考虑维护alfa,然后加上第二维的限制进行剪枝,然后卡常。。。
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
const double inf=1e18;
inline int read(){
char c=getchar();int t=0,f=1;
while((!isdigit(c))&&(c!=EOF)){if(c=='-')f=-1;c=getchar();}
while((isdigit(c))&&(c!=EOF)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
return t*f;
}
int n,k,a[maxn][3];
double dp[maxn];
double t[maxn];
#define ls rt<<1
#define rs rt<<1|1
inline void pushup(int rt){
t[rt]=max(t[ls],t[rs]);
}
int ps[maxn];
inline void build(int rt,int l,int r){
t[rt]=1e18;
if(l==r){
ps[l]=rt;
return;
}
int mid=(l+r)>>1;
build(ls,l,mid);build(rs,mid+1,r);
pushup(rt);
}
inline void modify(int rt,int l,int r,int x,double val){
double dis=0;
if(l<=x&&x<=r)dis=0;
else dis=min(abs(x-l),abs(r-x));
if(t[rt]<val*val+dis*dis)return ;
if(l==r){t[rt]=val*val+dis*dis;return ;}
int mid=(l+r)>>1;
modify(ls,l,mid,x,val);
modify(rs,mid+1,r,x,val);
pushup(rt);
}
struct node{
double fi;
int se;
node(double f=0,int s=0){fi=f;se=s;}
}beta[maxn][55];
int sz[maxn];
int up[maxn],down[maxn];
void build2(int rt,int l,int r){
up[rt]=-1;down[rt]=1e9;t[rt]=inf;
if(l==r){
return;
}
int mid=(l+r)>>1;
build2(ls,l,mid);build2(rs,mid+1,r);
}
void modify2(int rt,int l,int r,int x,int y,double val){
t[rt]=min(t[rt],val);
up[rt]=max(up[rt],y);
down[rt]=min(down[rt],y);
if(l==r){sz[l]++;beta[l][sz[l]]=node(val,y);return ;}
int mid=(l+r)>>1;
if(x<=mid)modify2(ls,l,mid,x,y,val);
else modify2(rs,mid+1,r,x,y,val);
}
double now;
inline void query2(int rt,int l,int r,int x,int y){
if(up[rt]==-1)return ;
double dis;
if(l<=x&&x<=r)dis=0;
else dis=min(abs(x-l),abs(r-x));
double dis2;
if(up[rt]>=y&&y>=down[rt])dis2=0;
else dis2=min(abs(up[rt]-y),abs(y-down[rt]));
if(t[rt]+dis*dis+dis2*dis2>=now){
return ;
}
if(l==r){
double tmp=dis*dis;
for(register int i=1;i<=sz[l];i++){
now=min(now,beta[l][i].fi+tmp+(beta[l][i].se-y)*(beta[l][i].se-y));
}
return ;
}
int mid=(l+r)>>1;
if(x<=mid){
query2(ls,l,mid,x,y);
query2(rs,mid+1,r,x,y);
}
else{
query2(rs,mid+1,r,x,y);
query2(ls,l,mid,x,y);
}
}
signed main(){
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
n=read(),k=read();
int mx=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=k;j++){
a[i][j]=read();
}
mx=max(mx,a[i][1]);
}
if(k==2)
{
build2(1,0,mx);
modify2(1,0,mx,0,0,0);
for(int i=1;i<=n;i++){
now=inf;
query2(1,0,mx,a[i][1],a[i][2]);
dp[i]=sqrt(now);
modify2(1,0,mx,a[i][1],a[i][2],dp[i]*dp[i]);
printf("%.4lf\n",dp[i]);
}
}
if(k==1){
dp[0]=0;
build(1,0,mx);
modify(1,0,mx,0,0);
for(int i=1;i<=n;i++){
dp[i]=1e18;
dp[i]=sqrt(t[ps[a[i][1]]]);
modify(1,0,mx,a[i][1],dp[i]);
}
for(int i=1;i<=n;i++){
printf("%.4lf\n",dp[i]);
}
}
return 0;
}
时间复杂度比较玄学,没有分析。。。