タイトル
仕事の山を見るために、列のX少数のは、あなたが彼を助けるために、スマートたい、頭痛です。列の数を考える\(A = \) [ \(A_1 \)、\ (A_2 \) ...... \(A_N \) ]、変換F(A、K)= [定義\(A_2 \)を、\ (A_3 \) ...... \(a_k \)、\ (A_1 \)、\ (A_ {2} + K \)、\ (A_。3} {K + \) ... \(A_ 2K} {\)、\ (A_ { 1} + k個の\) ......]、すなわち、セグメント、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≤のに\(6 10 ^ \) 。
問題の解決策
注意深い観察は、すべての時間が前期間の最初の数は、最初の期間の後に移動し、見出すことができます。
期間の後の最初の位置の前の期間移動の最初の数字は、各最初のセグメント、n個の全体動きのカラムの最終的な合計数の後に前のセグメントの最初の数に移動するたびに-1次。2回だけ大規模な配列を開き、列数と現在のヘッド位置を記録。
(私は、スクロール配列を使用し、Dalaoコードがちょうど見つけスワップを利用することができました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;
}