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;
}
posted @ 2025-07-16 19:17  XP3301_Pipi  阅读(24)  评论(1)    收藏  举报
Title