题目
小X看到堆成山的数列作业十分头疼,希望聪明的你来帮帮他。考虑数列(A=)[(A_1),(A_2)……(A_n)],定义变换f(A,k)=[(A_2),(A_3)……(A_k),(A_1),(A_{k+2}),(A_{k+3})……(A_{2k}),(A_{k+1})……],也就是把A分段,每段k个(最后如果不足k个,全部分到新的一段里,详见样例),然后将每段的第一个移动到该段的最后一个。
现在,小X想知道 f(f(f(f([1,2,3,⋯,n],2),3),⋯),n)的结果。
输入
输入一行包含一个整数n。
输出
输出一行包含n 个整数,表示最终的数列。
样例
输入 | 输出 |
---|---|
4 | 4 2 3 1 |
数据范围
对于60%的数据,1≤n≤(10^3)。
对于100%的数据,1≤n≤(10^6)。
题解
仔细观察可以发现,每次前一段的第一个数移动到了后一段的第一个。
每次将前一段的第一个数移动到后一段的第一个的位置,那么每次将前一段的第一个数移动到后一段的第一个,最终整个数列总的就移动了n-1次。只需开一个两倍大的数组,再记录当前数列的头部位置即可。
(我这里用了滚动数组,看了一位Dalao的代码,发现只需用swap即可STL大法好)
#include<cstdio>
#include<algorithm>
using namespace std;
int n,head,inv=0;
int a[2000010]={0},t[2]={0};
void init(){
scanf("%d",&n);
for(int i=1;i<=n;i++) a[i]=i;
head=1;
}
void work(int k){
for(int i=head;i<=n+head-1;i+=k){
t[inv]=a[i];
a[i]=t[inv^1];
inv^=1;
if(i+k>n+head-1) a[n+head]=t[inv^1];
}
}
int main(){
init();
for(int i=2;i<=n;i++){
work(i);
head++;
}
for(int i=head;i<n+head-1;i++) printf("%d ",a[i]);
printf("%d",a[n+head-1]);
return 0;
}