P3098 [USACO13DEC] The Bessie Shuffle G 做题记录
P3098 [USACO13DEC] The Bessie Shuffle G
Description
https://www.luogu.com.cn/problem/P3098
Solution
转化一下题意:有一个长度为 \(m\) 的窗口从 \(1\) 开始滑动,每次窗口内的牌进行 \(A\) 类洗牌,然后窗口向右滑动一格。
题目问的是最终得到的序列中第 \(x\) 个元素的值。由于原始序列是 \(1\sim n\),所以求出初始哪一个元素到达了这个位置即可。这启发我们倒序考虑。
设 \(g_{p_i}=i\),即把 \(p\) 的方向倒过来。
设元素 \(i\) 位于窗口的第 \(k\) 个位置,那么接下来一轮洗牌它将到达 \(g_k\),然后窗口移动,最终到达 \(g_k +1\)。若到达 \(m+1\) 则说明移出了窗口,过程终止。
每个位置跳一步到达的位置是固定的,可以倍增处理。
具体细节看代码,时间复杂度 \(O((m+q)\log n)\)。
int n,m,Q;
int g[N],f[N][35];
signed main(){
read(n),read(m),read(Q);
for(int i=1;i<=m;i++){
int x; read(x);
g[x]=i;
}
for(int i=1;i<=m;i++) f[i][0]=g[i]+1;
f[m+1][0]=m+1;
for(int j=1;j<=31;j++)
for(int i=1;i<=m+1;i++)
f[i][j]=f[f[i][j-1]][j-1];
while(Q--){
int x; read(x);
x=n-x+1;
int p,c;
if(x<n-m+1) p=1,c=x;
else p=m-(n-x),c=n-m+1;
for(int i=30;i>=0;i--){
if(c>=(1<<i)&&f[p][i]!=m+1){
p=f[p][i];
c-=(1<<i);
}
}
if(!c) printf("%d\n",p-1);
else printf("%d\n",c+m-1);
}
return 0;
}

浙公网安备 33010602011771号