P10198 [USACO24FEB] Infinite Adventure P 题解
深刻。
题意
有 \(n\) 个城市,每个城市 \(i\) 有一个周期 \(T_i\) 且 \(T_i\) 是 \(2\) 的幂次。城市 \(i\) 有 \(T_i\) 个传送门为 \(c_{i,0},\dots,c_{i,T_i−1}\)。若在日期 \(t\) 进入城市 \(i\),则花费一天到达城市 \(c_{i,t\bmod T_i}\)。给定 \(q\) 个询问 \((v,t,\Delta)\),问从日期 \(t\) 出发,在城市 \(v\) 执行 \(\Delta\) 次传送后到达的城市。\(1\leq t,\Delta\leq 10^{18},q\leq 5\times 10^4\)。
初步思考
考虑到值域非常大,直接模拟肯定不行,想到倍增。一个自然的想法是定义操作 \(jump(i,r,k)\) 表示在城市 \(i\) 且 \(t\bmod T_i=r\),走 \(2^k\) 步到达的城市。但是这样会有问题。例如当前 \(T_i=4,t\bmod 4=1\),那么 \(t\) 可以是 \(1,5,9,\dots\)。如果下一步走到 \(T_j=8\),那么我们要知道 \((t+1)\bmod 8\),当 \(t=1\) 时等于 \(2\),\(t=5\) 时等于 \(6\),结果不一样。而只有 \(T_j\leq T_i\) 才能确定。而这个题有一个很好的性质就是 \(T_i=2^k\),所以两个周期之间可以整除,所以比 \(T_i\) 小的都可以处理,比它大的信息会丢失。换句话说,如果现在已知 \(t\bmod T_i\),则所有满足 \(T'|T\) 的城市都是确定的,因为 \(t\bmod T'=(t\bmod T)\bmod T'\)。
状态建立与转移
我们定义 \(T\) 相同的城市为同层,按经过同层的城市为一步。如果中间有更低层的(\(T_j< T_i\))则可以直接压缩掉,不影响信息,直接到达最近的同层城市。还要记一个真实步数代表实际走了多少个城市,方便更新 \(\Delta\)。即 \(f_{k,u,r}\) 表示从 \(u\) 开始走 \(2^k\) 个同层城市,\(t\bmod T_u=r\) 的位置,\(g_{k,u,r}\) 表示真实步数。在 \(k=0\) 时,根据定义,遇到同一层就记录,如果中途遇到高层的就停下来。那么转移就比较显然,按周期从小到大处理,设 \(v=f_{k-1,u,r},l=g_{k-1,u,r}\),转移为 $$\begin{aligned}f_{k,u,r}&=f_{k-1,v,(r+l)\bmod T_u}\\ g_{k,u,r}&=g_{k-1,v,(r+l)\bmod T_u}+l\end{aligned}$$
查询
对于查询 \((v,t,\Delta)\),维护当前城市 \(x\),日期 \(t'\) 以及剩余步数 \(\Delta'\)。从最大的 \(LOG\) 开始倒着枚举 \(i\),如果 \(g_{i,x,t'\bmod T_x}\leq \Delta'\),说明可以走,更新一下。关键优化,如果更新后仍然满足条件,让 \(i\leftarrow i+1\),相当于保持不变,继续走 \(2^i\) 次。如果所有的都走不动了就手动跳一步,即 \(x=c_{x,t'\bmod T_x}\)。直到 \(\Delta'=0\)。
复杂度分析
预处理部分处理 \(f_0,g_0\) 时是 \(O(\sum T_i\cdot \log \max T)\),倍增合并是 \(O(\sum T_i\cdot \log V)\),\(V\) 是 \(\Delta\) 的值域。而查询部分不加优化最坏每一轮可能只能走 \(\log V\) 步,复杂度退化至 \(O(\Delta)\)。加上优化会不停复用一个 \(i\),复杂度是 \(O(\log V)\)。所以总体复杂度 $$O\Big(\big(\sum T_i+q\big)\log V\Big)$$
代码
#include<bits/stdc++.h>
#define L(a,b,c,d) for(int a=b;a<=c;a+=d)
#define R(a,b,c,d) for(int a=b;a>=c;a-=d)
using namespace std;
typedef long long i64;
typedef __int128 i128;
const int N=1e5+5,LOG=61;
const i64 INF=1ll<<60;
void solve();
int n,q,maxT;
vector<int> T,c[N],f[LOG][N];
vector<i64> g[LOG][N];
signed main(){
int Test=1;
// scanf("%d",&Test);
while(Test--) solve();
return 0;
}
void build(){
L(i,1,maxT,i){
L(j,1,n,1){
if(i!=T[j]) continue;
L(k,0,T[j]-1,1){
int x=c[j][k];
i64 len=1,t=k+1;
while(T[x]<T[j]){
i64 y=g[LOG-1][x][t%T[x]];
if(len+y>=INF) break;
len+=y;
x=f[60][x][t%T[x]];
t+=y;
}
f[0][j][k]=x;
g[0][j][k]=len;
}
}
L(l,1,LOG-1,1){
L(j,1,n,1){
if(i!=T[j]) continue;
L(k,0,T[j]-1,1){
int x=f[l-1][j][k];
i64 y=g[l-1][j][k];
if(T[x]!=T[j]){
f[l][j][k]=x;
g[l][j][k]=y;
continue;
}
f[l][j][k]=f[l-1][x][(k+y)%T[x]];
g[l][j][k]=min(g[l-1][x][(k+y)%T[x]]+y,INF);
}
}
}
}
}
int query(int x,i64 t,i64 del){
while(del){
R(i,LOG-1,0,1){
int y=f[i][x][t%T[x]];
i64 w=g[i][x][t%T[x]];
if(w<=del){
x=y;
t+=w;
del-=w;
}
if(g[i][x][t%T[x]]<=del) i++;
}
if(del){
x=c[x][t%T[x]];
t++;
del--;
}
}
return x;
}
void solve(){
scanf("%d%d",&n,&q);
T.resize(n+1);
L(i,1,n,1){
scanf("%d",&T[i]);
maxT=max(maxT,T[i]);
}
L(i,1,n,1){
c[i].resize(T[i]);
L(j,0,T[i]-1,1){
scanf("%d",&c[i][j]);
}
L(j,0,LOG-1,1){
f[j][i].resize(T[i]);
g[j][i].resize(T[i]);
}
}
build();
while(q--){
int x;
i64 t,del;
scanf("%d%lld%lld",&x,&t,&del);
printf("%d\n",query(x,t,del));
}
}
本文来自博客园,作者:jess1ca1o0g3,转载请注明原文链接:https://www.cnblogs.com/jess1ca1o0g3/p/22634252

浙公网安备 33010602011771号