把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【思维·模拟】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;
}
posted @ 2019-08-06 21:05  Starlight_Glimmer  阅读(9)  评论(0编辑  收藏  举报  来源
浏览器标题切换
浏览器标题切换end