题解:P8522 [IOI2021] 地牢游戏
看到大于等于
于是考虑我们认为一次过程是走若干步,在走到过程中能力值始终处在
找极大过程可以直接考虑倍增,具体而言,对于每个块处理
由于观察到
#include<bits/stdc++.h>
using namespace std;
//#define int long long
//#define lowbit(x) (x&(-x))
//#define bp push_back
//#define sz size
//#define cl clear
const int maxn = 4e5+14;
const int warma = 64;
int dp[6][maxn][25];//在第 i 块中点 u 出发跳 2^j 步抵达的点
long long f[6][maxn][25];//在第 i 块中点 u 出发跳 2^j 步获得加成
long long g[6][maxn][25];//在第 i 块中点 u 出发跳 2^j 步,中途不超过块,遇到 s_i 在块内的必失败,初始节点最大能力值
long long _pow[6];
vector<int> s,p,w,l;
int n;
void init(int N, vector<int> S, vector<int> P, vector<int> W, vector<int> L){
n=N,s=S,p=P,w=W,l=L;
_pow[0]=1;
for(int i=1;i<5;i++) _pow[i]=_pow[i-1]*warma;
_pow[5]=1e18;
for(int bl=0;bl<5;bl++){
for(int i=0;i<n;i++) dp[bl][i][0]=(s[i]<_pow[bl]?w[i]:l[i]),f[bl][i][0]=(s[i]<_pow[bl]?s[i]:p[i]),g[bl][i][0]=((_pow[bl]<=s[i]&&s[i]<_pow[bl+1])?min(1ll*s[i]-1,_pow[bl+1]-1):_pow[bl+1]-1);
for(int j=1;j<25;j++){
for(int i=0;i<n;i++){
dp[bl][i][j]=dp[bl][dp[bl][i][j-1]][j-1];
f[bl][i][j]=f[bl][i][j-1]+f[bl][dp[bl][i][j-1]][j-1];
g[bl][i][j]=min(g[bl][i][j-1],g[bl][dp[bl][i][j-1]][j-1]-f[bl][i][j-1]);
}
dp[bl][n][j]=n;
f[bl][n][j]=0;
g[bl][n][j]=1e18;
}
}
return ;
}
int chk(long long z){
int mx=0;
for(int i=0;i<6;i++){
if(z>_pow[i]) mx=i;
}
return mx;
}
long long ask(int x,long long z,int h){
for(int i=24;i>=0;i--){
if(z<=g[h][x][i]) z+=f[h][x][i],x=dp[h][x][i];
}
if(x==n) return z;
if(z>=s[x]) z+=s[x],x=w[x];
else z+=p[x],x=l[x];
if(x==n) return z;
else return ask(x,z,chk(z));
}
long long simulate(int x, int z){
return ask(x,z,chk(z));
}