BZOJ4095 : [Usaco2013 Dec]The Bessie Shuffle

首先将排列和整个序列以及询问都反过来,问题变成给定一个位置$x$,问它经过若干轮置换后会到达哪个位置。

每次置换之后窗口都会往右滑动一个,因此其实真实置换是$p[i]-1$。

对于每个询问,求出轮数,倍增找到最终位置,注意当中途走到$0$时,说明离开了窗口,应及时终止。

时间复杂度$O((m+q)\log n)$。

 

#include<cstdio>
const int N=100010,M=30;
int n,m,q,i,j,x,r,k,a[M][N];
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
int main(){
  read(n),read(m),read(q);
  for(i=m;i;i--)read(x),a[0][m-x+1]=i-1;
  for(i=1;i<M;i++)for(j=1;j<=m;j++)a[i][j]=a[i-1][a[i-1][j]];
  while(q--){
    read(x);
    if(x<m)r=m;else r=x,x=m;
    k=n-r+1;
    for(i=M-1;~i;i--)if((1<<i)<=k&&a[i][x])x=a[i][x],k-=1<<i,r+=1<<i;
    if(k)x=a[0][x],r++;
    printf("%d\n",n-(r-m+x)+1);
  }
  return 0;
}

  

posted @ 2017-09-03 04:07  Claris  阅读(638)  评论(0编辑  收藏  举报