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;
}

  

上一篇:ldd获得可执行程序的所有库并输出到指定目录


下一篇:异步编程系列第04章 编写Async方法