UOJ #664. 【IOI2021】dungeons

题面传送门
很容易发现这个题目的特殊点是打败一个敌人就可以加上它的能力值。
也就是说如果我们以\([2^i,2^{i+1}]\)分段,那么如果我们打败了一个段里面的一个敌人那么就可以上一个段。
不难想到对于每个段处理一个倍增数组,并在倍增时维护一个值\(G\)表示只有当前能力值小于等于\(G\)才能继续走。一旦停下要么是可以晋级,要么走到了终点。
时间复杂度\(O(n\log^2V+q\log^2V)\)
然后你发现不对劲,空间复杂度\(O(n\log^2V)\)根本过不去。
考虑改变分段的基数,发现如果以\([B^i,B^{i+1}]\)分段,那么一个段内会停下\(B\)次。
所以时间复杂度为\(O(n\log_{B}V\log V+qB\log V\log_{B}V)\),实测取\(B=26\)最优。
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define RI re int
#define ll long long
#define db double
#define lb long db
#define N 400000
#define M 500000
#define mod 998244353
#define Mod (mod-1)
#define eps (1e-5)
#define U unsigned int
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define d(x,y) (m*x+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound  
using namespace std;
int n,m,k,fa[6][25][N+5],S[N+5],P[N+5],W[N+5],L[N+5];ll Z,Up[30],G[6][25][N+5],F[6][25][N+5];const int B=26;
void init(int m,vector<int> s,vector<int> p,vector<int> w,vector<int> l) {
	RI i,j,h;n=m;for(i=0;i<n;i++)S[i]=s[i],P[i]=p[i],W[i]=w[i],L[i]=l[i];
	for(i=0;i<=5;i++) {
		Up[i]=(i^5?pow(B,i+1):1e18);for(j=0;j<n;j++){
			fa[i][0][j]=(S[j]>Up[i-1]?L[j]:W[j]);F[i][0][j]=(S[j]>Up[i-1]?P[j]:S[j]);
			G[i][0][j]=(S[j]>Up[i-1]&&S[j]<=Up[i]?min(S[j]-1,Up[i]-F[i][0][j]):Up[i]-F[i][0][j]);fa[i][0][j]==n&&(G[i][0][j]=-1e18);
		}
		for(j=1;j<=24;j++)for(h=0;h<n;h++) fa[i][j][h]=fa[i][j-1][fa[i][j-1][h]],F[i][j][h]=F[i][j-1][h]+F[i][j-1][fa[i][j-1][h]],G[i][j][h]=min(G[i][j-1][h],G[i][j-1][fa[i][j-1][h]]-F[i][j-1][h]);
	}
}
ll simulate(int x, int z) {
	RI i,j;Z=z;for(i=0;;){
		if(Z>Up[i]){i++;continue;}if(x==n) return Z;//cerr<<x<<' '<<z<<'\n';
		for(j=24;~j;j--) Z<=G[i][j][x]&&(Z+=F[i][j][x],x=fa[i][j][x]);Z>=S[x]?(Z+=S[x],x=W[x]):(Z+=P[x],x=L[x]);
	}
}
上一篇:推荐几个大学生接私活的网站,“你有码,我有钱”


下一篇:CTF-Crypto:hill的秘密