[IOI2021]地牢游戏
2021/11/17 23:13:58
本文主要是介绍[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; }
这篇关于[IOI2021]地牢游戏的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南