T1 [JZOJ3403] 数列变换

题目描述

  小 $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)$ 的结果。

数据范围

  对于 $60 \%$ 的数据,$1 \leq n \leq 10^3$

  对于 $100 \%$ 的数据,$1 \leq n \leq 10^6$

分析

  如果我们在原数组中暴力移动数字,那么时间复杂度为 $O(n^2)$

  但手推一下会发现,每次移动时大部分项的位置是不变的,只有每段第一个数的位置发生改变

  所以每次只需要将每段的第一项向后移动,这时数组会整体向后移动一项,因此要开一个两倍长的数组

  时间复杂度为 $O(n \sum\limits_{i=2}^{n} \frac{n}{i}) \doteq O(n \; ln \; n)$

2019-08-04 纪中NOIP模拟B组
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 1000005

int n;
int a[2 * N];

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) a[i + 1] = i;
    for (int i = 2; i <= n; i++) {
        int j = i + n / i * i;
        a[i + n] = a[j];
        for (j -= i; j >= i; j -= i) a[j + i] = a[j];
    }
    for (int i = n + 1; i <= 2 * n; i++)
        printf("%d ", a[i]);
    
    return 0;
}
View Code

相关文章: