【思维·模拟】jzoj3403数列变换 纪中集训提高B组
Description
小X 看到堆成山的数列作业十分头疼,希望聪明的你来帮帮他。考虑数列A=[A1,A2,…,An],定义变换f(A,k)=[A2,A3,.Ak,A1,Ak+2,Ak+3,A2k,Ak+1,…],也就是把a 分段,每段k 个(最后如果不足k 个,全部分到新的一段里,见样例),然后将每段的第一个移动到该段的最后一个。
现在,小 X想知道 f (f (f (f ([1,2,3,⋯,n],2),3),⋯),n)的结果。
Input
输入一行包含一个整数n 。
Output
输出一行包含n 个整数,表示最终的数列。
Sample Input
4
Sample Output
4 2 3 1
【样例说明】
f ([1,2,3,4],2) = [2,1,4,3]
f ([2,1,4,3],3) = [1,4,2,3](3单独被分在一组,移动到组的最后一位,仍然是3)
f ([1,4,2,3],4) = [4,2,3,1]
Data Constraint
对于60%的数据,1≤ n ≤10^3。
对于100%的数据,1≤ n ≤10^6。
考场上只写了60分的暴力分,没有想到什么特别的优化。
万万没想到正解其实很简单,我们发现移动数组这个操作是非常浪费时间的,所以我们就不移它,只移每一段最前面的数,直接开两倍数组把最前面的数往后面搞就可以了。
而且代码量还比暴力少。
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 2000005
#define LL long long
int n,a[MAXN];
int main()
{
scanf("%d",&n);
if(n==1){printf("1\n"); return 0;}
if(n==2){printf("2 1\n"); return 0;}
for(int i=1;i<=n;i++)
a[i]=i;
for(int k=2;k<=n;k++)
{
int i,tmp,past;
for(i=k-1;i+k<=n+k-2;i+=k)//枚举起点
{
tmp=a[i];
if(i!=k-1) a[i]=past;
past=tmp;
}
a[n+k-1]=a[i];
a[i]=tmp;
}
for(int i=n;i<=2*n-1;i++)
printf("%d ",a[i]);
return 0;
}
转载请注明出处,有疑问欢迎探讨
博主邮箱 2775182058@qq.com