[IOI2021]地牢游戏
作者:互联网
地牢游戏
题解
首先,我们根据
s
u
b
t
a
s
k
3
,
4
subtask\,3,4
subtask3,4,应该很容易想到一种倍增的做法去解决我们的问题。
对于这几个图,我们的分层是相当少的,所以我们可以将我们整个过程分成至多
6
6
6个阶段,对于每个阶段单独倍增直到超越这个阶段,或者说抵达我们的终点。
我们考虑将我们的倍增做法延伸到我们的正解上,显然,由于当我们胜利后会直接加上一个
s
i
s_i
si,所以可以发现这实际上是一个加倍的过程,我们先前打不掉,然后变得打得掉最多只会经过
log
S
\log\,S
logS层。
我们可以把我们的整个段化划分成
log
S
\log\,S
logS个
[
2
k
,
2
k
+
1
)
[2^k,2^{k+1})
[2k,2k+1)的区间,每次进入这个区间后我们就看成我们可以
w
i
n
win
win下所有
s
<
2
k
s< 2^k
s<2k的点,会输掉所有
s
⩾
2
k
s\geqslant 2^k
s⩾2k的点。
我们一直倍增到我们跑到一个可以打赢的
[
2
k
,
2
k
+
1
)
[2^k,2^{k+1})
[2k,2k+1)点的位置,显然,这种情况我们就可以跳出这个区间了。或者我们的值超过
2
k
+
1
2^{k+1}
2k+1,亦或者我们抵达了我们的终点为止。
判断我们是否跑到一个可以打赢的
[
2
k
,
2
k
+
1
)
[2^k,2^{k+1})
[2k,2k+1)点位置只需要记录下我们初始值是多少时能够战胜我们面前的该点,这东西显然也是可以倍增处理的。
这样的话,预处理和询问都是带个
O
(
log
2
n
)
O\left(\log^2n\right)
O(log2n),不说时间,就是空间也是会炸的,我们考虑优化。
显然,对于一个
[
2
k
,
2
k
+
1
)
[2^k,2^{k+1})
[2k,2k+1),真正重要的是我们所有的在
[
2
k
,
2
k
+
1
)
[2^k,2^{k+1})
[2k,2k+1)内的关键点。
我们可以只对于这些点建立倍增数组,这样的话每个点就只需要建立一个倍增数组。
对于一个不在当前区间内的点,我们就暴力处理出这个点在这个区间内跑时能够到的第一个关键点。
当然,如果一个点在跑的过程中就大于我们的
2
k
+
1
2^{k+1}
2k+1了,我们可以把它扔到下一个
k
+
1
k+1
k+1的图上去处理,显然,当它大于后它跑的规则就是下一个图的规则了。
当然不是找到那些非关键点中它超越范围的点,而是就是当前关键点的下一个点或者我们的起始点,因为非关键点跑的规则在我们大于我们的
2
k
+
1
2^{k+1}
2k+1时是与我们当前图是一样的,我们之后的过程中也不会经过我们的关键点了,自然可以这样处理。
当然,我们在每个图中都可以将终点看成一个关键点,方便转移,只是不需要处理终点的倍增数组罢了。
时间复杂度 O ( n log n + q log 2 n ) O\left(n\log\,n+q\log^2n\right) O(nlogn+qlog2n),空间复杂度 O ( n log n ) O\left(n\log\,n\right) O(nlogn),由于笔者开了 4 4 4个大小为 n log n n\log\,n nlogn的数组,空间基本是卡着的。
源码
#include "dungeons.h"
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
typedef vector<int> vi;
#define MAXN 400005
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
const LL INF=0x3f3f3f3f3f3f;
int n,f[MAXN][25],nxt[MAXN][25],s[MAXN],p[MAXN];
LL dis[MAXN][25],mx[MAXN][25],dp[MAXN],g[MAXN][25],w[MAXN],l[MAXN];
vector<pii>G[MAXN];vi tmp;queue<int>qq;
void init(int _n,vi _s,vi _p,vi _w,vi _l){
n=_n;
for(int i=0;i<n;i++)s[i]=_s[i];
for(int i=0;i<n;i++)p[i]=_p[i];
for(int i=0;i<n;i++)w[i]=_w[i];
for(int i=0;i<n;i++)l[i]=_l[i];
for(int i=n-1;i>=0;i--)dp[i]=dp[w[i]]+s[i];
for(int i=0;i<24;i++)f[n][i]=n;w[n]=l[n]=n;
for(int i=0;i<24;i++){
for(int j=0;j<=n;j++)dis[j][i]=INF,G[j].clear();
for(int j=0;j<n;j++)
if(s[j]>=(1<<i+1))G[l[j]].pb(mkpr(j,p[j]));
else if(s[j]<(1<<i))G[w[j]].pb(mkpr(j,s[j]));
else qq.push(j),dis[j][i]=0,nxt[j][i]=j;
qq.push(n);dis[n][i]=0;nxt[n][i]=n;
while(!qq.empty()){
int u=qq.front(),siz=G[u].size();qq.pop();
for(int j=0;j<siz;j++){
int v=G[u][j].fir,wp=G[u][j].sec;qq.push(v);
dis[v][i]=dis[u][i]+wp;nxt[v][i]=nxt[u][i];
}
}
tmp.clear();
for(int j=0;j<n;j++)
if((1<<i)<=s[j]&&s[j]<(1<<i+1))
f[j][0]=nxt[l[j]][i],g[j][0]=dis[l[j]][i]+1ll*p[j],
mx[j][0]=s[f[j][0]]-g[j][0],tmp.pb(j);
int siz=tmp.size();
for(int k=1;k<24;k++)
for(int j=0;j<siz;j++){
int u=tmp[j];f[u][k]=f[f[u][k-1]][k-1];
g[u][k]=g[u][k-1]+g[f[u][k-1]][k-1];
mx[u][k]=min(mx[u][k-1],mx[f[u][k-1]][k-1]-g[u][k-1]);
}
}
}
LL simulate(int _x,int _z){
int x=_x;LL z=_z;
for(int j=0;j<24;j++){
if(s[x]>=(1<<j)&&s[x]<(1<<j+1)){if(z>=s[x])z+=s[x],x=w[x];else z+=p[x],x=l[x];}
if(z+dis[x][j]>=(1<<j+1))continue;
z+=dis[x][j];x=nxt[x][j];
if(z>=s[x]){z+=s[x];x=w[x];continue;}
for(int k=23;k>=0;k--)
if(z<mx[x][k]&&z+g[x][k]<(1<<j+1)&&f[x][k]!=n)
z+=g[x][k],x=f[x][k];
if(z+g[x][0]>=(1<<j+1)){if(z>=s[x])z+=s[x],x=w[x];else z+=p[x],x=l[x];continue;}
z+=g[x][0];x=f[x][0];if(x==n)break;
}
z+=dp[x];
return z;
}
标签:游戏,int,地牢,IOI2021,MAXN,log,倍增,我们,2k 来源: https://blog.csdn.net/Tan_tan_tann/article/details/121389129