B、Infoplane in Tina Town-----(BestCoder Round #51 (div.2) )

Infoplane in Tina Town

 Time Limit: 7000/3500 MS (Java/Others)
 
 Memory Limit: 524288/524288 K (Java/Others)
問題描述
Tina Town 的鎮中有一塊表面平整光滑的大石頭, 當人面向它走進時, 石頭的表面就會亮起, 顯示出它的用途. 這塊石頭是前人留下來的東西,是Tina Town算力和控制系統的核心, 同時它也可以顯示Tina Town的大小事和行人關注的內容,也可以作爲公共的計算機使用 ,極大地方便了人們的生活(特別是上街忘帶終端的人們啦).

Tina和Town在這塊大石頭上玩一個遊戲. 石頭上首先顯示出了1到n排列的n個數,Town則隨機交換了一些數, 然後Town通過宏將這個交換的過程記錄下來了. Town 問 Tina: 你知道執行幾次這個宏, 這些數會恢復最早的排列嘛? Tina是一個蠢蠢的女孩子, 當然不知道啦, 於是她想向你請教呢.

由於答案可能很大,你只需要輸出答案對於3*2^{30}+1=32212254733230+1=3221225473(一個素數)的模就行了.
輸入描述
第一行一個數TT,表示數據組數.T\le 5T5

接下來一組數據兩行,第一行一個整數nn,表示排列的長度.n\le 3\times 10^6n3×106

第二行一個nn個數表示一個排列A_1... A_nA1...An,保證數字兩兩不同且對於所有的A_iAi都有1\le A_i\le n1Ain.
輸出描述
對於每組數據輸出一行一個數ansans,表示答案.
輸入樣例
2
3
1 3 2
6
2 3 4 5 6 1
輸出樣例
2
6
Hint
數據規模較大建議使用讀入優化.

分析:首先,這道題讀題怎麼都不理解題意,看了幾遍管理員的解釋總算明白了,ORZ。

題意:給一個數組,經過數字循環後,變成原來1~n的遞增序列。數字循環只能是每一次把區間內的第一個數字移到最後(可能也可以把最後的數字移到第一個),幾個區間是同時移動的。

第一個數據 1 3 2 -> 1 2 3 長度爲2 第二個數據 2 3 4 5 6 1 -> 3 4 5 6 1 2 -> 4 5 6 1 2 3 -> 5 6 1 2 3 4 -> 6 1 2 3 4 5 -> 1 2 3 4 5 6 長度爲6

另外數據2 1 4 5 3的過程是 2 1 4 5 3-> 1 2 5 3 4-> 2 1 3 4 5 -> 1 2 4 5 3 -> 2 1 5 3 4-> 1 2 3 4 5 長度爲6


官方題解:

給出一個置換,求它的循環長度。數據範圍 3\times 10^63×106

其實沒有什麼好說的,就分解成循環求長度的最小公倍數就好了。對於這個模數要用unsigned int存,這個最小公倍數的求法不能用歐幾里得,直接每次分解質因數,用線性篩預處理一下就好了。

時間複雜度:O(n)O(n).分析

對於第一部分尋找循環每個點都恰好遍歷一次,O(n)O(n);

第二部分分解質因數,時間複雜度爲

\sum_{i=1}^kf(|p_k|)i=1kf(pk)f=O(\log{n})f=O(logn),\sum_{i=1}^k|p_k|=ni=1kpk=n.

顯然有f(|p_k|)\le p_kf(pk)pk,所以這部分時間複雜度O(n)O(n).

第三部分快速冪加乘法同樣分析.


CODE:(這是我直接求最小公倍數,始終沒有發現BUG,但一直WA,ORZ)

#include <iostream>
#include <cstdio>
#include <string.h>
#define ll long long
//#define mod 3221225473
using namespace std;

const ll mod=3221225473;
const int maxn=3000005;
ll n,a[maxn],num[maxn];
bool vis[maxn];

ll gcd(ll a,ll b){
    return b?gcd(b,a%b):a;
}

int main()
{
    //模下gcd是不正確的
    int t; scanf("%d",&t);
    while(t--){
        memset(vis,0,sizeof(vis));
        int cnt=0;
        scanf("%lld",&n);
        for(int i=1;i<=n;i++)
            scanf("%lld",&a[i]);
        for(int i=1;i<=n;i++){
            if(vis[i]) continue;
            ll k=i,sum=0;
            while(!vis[k]){
                vis[k]=1;
                k=a[k];
                sum++;
            }
            num[cnt++]=sum;
        }
        ll gcc=num[0];
        for(int i=1;i<cnt;i++){
            gcc=gcd(gcc,num[i]);
        }
        ll ans=num[0]/gcc;
        for(int i=1;i<cnt;i++){
            ans=(ans*num[i])%mod;
        }
        if(cnt==1) printf("%lld\n",num[0]);
        else printf("%lld\n",ans);
    }
    return 0;
}

CODE:

#include <iostream>
#include <cstdio>
#include <string.h>
#define ll long long
//#define mod 3221225473
using namespace std;

const ll mod=3221225473;
const int maxn=3000005;
ll n,a[maxn],num[maxn];
bool vis[maxn];

ll qpow_mod(ll x,ll y){
    ll ret=1;
    while(y){
        if(y&1)
            ret=(ret*x)%mod;
        x=(x*x)%mod;
        y>>=1;
    }
    return ret;
}

int main()
{
    int t; scanf("%d",&t);
    while(t--){
        memset(vis,0,sizeof(vis));
        memset(num,0,sizeof(num));
        int cnt=0;
        scanf("%lld",&n);
        for(int i=1;i<=n;i++)
            scanf("%lld",&a[i]);
        for(int i=1;i<=n;i++){
            if(vis[i]) continue;
            ll k=i,sum=0;
            while(!vis[k]){
                vis[k]=1;
                k=a[k];
                sum++;
            }
            for(int j=2;j<=sum;j++){
                int tmp=0;
                while(sum%j==0){
                    tmp++;
                    sum/=j;
                }
                if(tmp>num[j])
                    num[j]=tmp;
            }
        }
        ll ans=1;
        for(int i=2;i<=n;i++){
            if(num[i])
                ans=(ans*qpow_mod(i,num[i]))%mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

CODE:(很納悶,用了輸入外掛,反而超時了)

#include <iostream>
#include <cstdio>
#include <string.h>
#define ll long long
//#define mod 3221225473
using namespace std;

const ll mod=3221225473;
const int maxn=3000005;
ll n,a[maxn],num[maxn];
bool vis[maxn];

ll qpow_mod(ll x,ll y){
    ll ret=1;
    while(y){
        if(y&1)
            ret=(ret*x)%mod;
        x=(x*x)%mod;
        y>>=1;
    }
    return ret;
}

inline int read(){
    char ch;
    int num=0;
    while((ch=getchar())<'0'||ch>'9');
    while(ch>='0'&&ch<='9')
        num=num*10+(ch-'0'),ch=getchar();
    return num;
}

int main()
{
    int t; scanf("%d",&t);
    while(t--){
        memset(vis,0,sizeof(vis));
        memset(num,0,sizeof(num));
        int cnt=0;
        scanf("%lld",&n);
        for(int i=1;i<=n;i++)
            a[i]=read();
        for(int i=1;i<=n;i++){
            if(vis[i]) continue;
            ll k=i,sum=0;
            while(!vis[k]){
                vis[k]=1;
                k=a[k];
                sum++;
            }
            for(int j=2;j<=sum;j++){
                int tmp=0;
                while(sum%j==0){
                    tmp++;
                    sum/=j;
                }
                if(tmp>num[j])
                    num[j]=tmp;
            }
        }
        ll ans=1;
        for(int i=2;i<=n;i++){
            if(num[i])
                ans=(ans*qpow_mod(i,num[i]))%mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章