Day4 T1 数列变换

题目

  小X看到堆成山的数列作业十分头疼,希望聪明的你来帮帮他。考虑数列 \(A = [A_1, A_2 \dots A_n]\),定义变换 \(f(A, k) = [A_2, A_3 \dots A_k, A_1, A_{k+2}, A_{k+3} \dots A_{2k}, A_{k+1} \dots]\),也就是把 \(A\) 分段,每段 \(k\) 个(最后如果不足 \(k\) 个,全部分到新的一段里,详见样例),然后将每段的第一个移动到该段的最后一个。
  现在,小X想知道 \(f(f(f(f([1,2,3,⋯,n],2),3),⋯),n)\) 的结果。

输入

输入一行包含一个整数 \(n\)

输出

输出一行包含 \(n\) 个整数,表示最终的数列。

样例

输入 输出
4 4 2 3 1

数据范围

对于 \(60%\) 的数据,\(1 \leq n \leq 10^3\)
对于 \(100%\) 的数据,\(1 \leq n \leq 10^6\)

题解

  仔细观察可以发现,每次前一段的第一个数移动到了后一段的第一个。
  每次将前一段的第一个数移动到后一段的第一个的位置,那么每次将前一段的第一个数移动到后一段的第一个,最终整个数列总的就移动了 \(n - 1\) 次。只需开一个两倍大的数组,再记录当前数列的头部位置即可。
(我这里用了滚动数组,看了一位Dalao的代码,发现只需用swap即可orz)

#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;
}
posted @ 2019-09-13 12:33  东方澂  阅读(209)  评论(0编辑  收藏  举报