1. 程式人生 > >hihocoder 1330 - 數組重排 - [hiho一下167周][最小公倍數]

hihocoder 1330 - 數組重排 - [hiho一下167周][最小公倍數]

gcd include 時間限制 一次 hiho 來看 不同 分類 for

題目鏈接:https://hihocoder.com/problemset/problem/1330

時間限制:10000ms 單點時限:1000ms 內存限制:256MB

描述

小Hi想知道,如果他每次都按照一種固定的順序重排數組,那麽最少經過幾次重排之後數組會恢復初始的順序?

具體來講,給定一個1 - N 的排列 P,小Hi每次重排都是把第 i 個元素放到第 Pi個位置上。例如對於 P = (2, 3, 1),假設初始數組是(1, 2, 3),重排一次之後變為(3, 1, 2),重排兩次之後變為(2, 3, 1),重排三次之後變回(1, 2, 3)。

被排數組中的元素可以認為是兩兩不同的。

輸入

第一行一個整數 N

,代表數組的長度。 (1 ≤ N ≤ 100)

第二行N個整數,代表1 - N 的一個排列 P

輸出

輸出最少重排的次數。

(PS.從實際提交的AC代碼來看,似乎重排次數至少為1,即必須進行重排操作)

樣例輸入
3
2 3 1
樣例輸出
3

題解:

不難看出,任意一個數,它經過有限步數就可以回到原來位置;

那麽,我們根據P=(2,3,1),那麽初始數列第一位a[1],第一步操作後它會變到第二位,第二步操作後它會變到第三位,第三步操作後它又會變回第一位,即回到原位;

如果忽視實際意義上的操作,簡單的從數字變換來講,即1→2→3→1,三個箭頭,代表操作了三步;

那麽更加廣泛的,例如P=(5,2,1,4,3,6),對於每一位有:

  1→5→3→1(3步);

  2→2(1步);

  3→1→5→3(3步);

  ……

  5→3→1→5(3步);

  6→6(1步);

然後當時我做到這一步就猜想是不是枚舉每一位要最少重排多少步能回到原位,取最大值即可;

不過顯然有反例,例如P=(3,2,1,5,6,4),這樣即:

  1→3→1(2步);

  2→2(1步);

  3→1→3(2步);

  4→5→6→4(3步);

  5→6→4→5(3步);

  6→4→5→6(3步);

這樣到底要重排多少次才能讓整個數列回到原來順序呢,顯然是lcm(2,1,2,3,3,3)=6,即每一位回到原點的最少步數的最小公倍數;

AC代碼:

 1 #include<cstdio>
 2 int n,p[105],ans=1;
 3 int gcd(int m,int n){return n?gcd(n,m%n):m;}
 4 int lcm(int m,int n){return m/gcd(m,n)*n;}
 5 int main()
 6 {
 7     scanf("%d",&n);
 8     for(int i=1;i<=n;i++) scanf("%d",&p[i]);
 9     for(int i=1;i<=n;i++)
10     {
11         int now=p[i],cnt=1;
12         while(1)
13         {
14             if(now==i) break;
15             else
16             {
17                 now=p[now];
18                 cnt++;
19             }
20         }
21         ans=lcm(ans,cnt);
22     }
23     printf("%d\n",ans);
24 }

PS.雖然用了GCD,但我都不好意思放數論分類裏,放其他分類裏吧……

hihocoder 1330 - 數組重排 - [hiho一下167周][最小公倍數]