1. 程式人生 > >JZOJ 3384. 【NOIP2013模擬】理科男

JZOJ 3384. 【NOIP2013模擬】理科男

目錄:

題目:

分析:

面我們對 a 數列的性質做一些討論。
如果(B,K)=1,對於任意的 i 都有 (a[i],B)=1
設 K’ 為 K 模 B 時的乘法逆元,即KKmodB=1。由乘法逆元的性質 K’ 存在且唯一。
假設最早出現重複的位置是 a[p]=a[q](p<q)
如果 p!=1,那麼 a[p1]=Ka[p]modB=K

a[q]modB=a[q1]
也就是出現了更早的重複,與題設矛盾。所以顯然有 p = 1。
這時,顯然原分數是一個純迴圈小數,且最短迴圈節長度是 q - 1。
設 x = q - 1。顯然 a[q]=a[1]KxmodB=a[1],於是 KxmodB=1
這就轉化成了求 K 模 B 的階的問題了。
由尤拉定理 Kphi(B)=1(modB),由階的性質 x|φ(B)
我們可以將 phi(B) 分解素因數,並初始化 x=φ(B)
之後考慮 phi(B) 的每個素因數 p。如果
K(x/p)=1(modB)
,就 x ← x / p,並繼續試除 p。
否則轉下一個素因數。這樣就可以求出 K 模 B 的階了,這就是最短迴圈節的長度。
如果 (B, K) > 1,那麼 (a[2], B) > 1。設 (a[2], B) = g,不難發現對於任意的 i ≥ 2,有 g | (a[i],
B)。
不妨設 B=B/ga[i]=a[i]/g(i2)
若此時 (B’, K) = 1,就轉化為了上面的情況。否則繼續這個過程。
如果上面的轉換進行了 T 次,由於 a[1] 到 a[T] 與後面 a 數列的迴圈無關。
卡一下範圍便會知道迴圈節的最後一個數字與混迴圈部分最後一個數字一定不相等。
於是原分數的混迴圈長度就是 T 了。
特殊地,如果在 T 次轉換之後得到的最後一個 B = 1,那麼之後 a 數列的值全為 0。這時
我們可以斷言原分數是一個小數點後有 T 位的有限小數。

程式碼:

#include<cstdio>
#include<cstring>
#define LL long long
using namespace std;int t,ans1;
LL gcd(LL a,LL b){return b?gcd(b,a%b):a;}
char c;
LL f,A,B,K;
inline LL read()
{
    f=0;
    while(c=getchar(),c<=47||c>=58);f=(f<<3)+(f<<1)+c-48;
    while(c=getchar(),c>=48&&c<=57) f=(f<<3)+(f<<1)+c-48;
    return f;
}
void write(LL x){if(x>9) write(x/10);putchar(x%10+48);return;}
LL phl(LL x)//尤拉函式 
{
    LL y=x;
    for(int i=2;(LL)i*i<=x;i++) if(x%i==0) {y=y/i*(i-1);do x/=i;while(x%i==0);}
    if(x>1) y=y/x*(x-1);
    return y;
}
LL mul(LL a,LL b,LL p)//快速冪 拆分乘數 
{
    LL c=0;
    for(;b;b>>=1,a=(a<<1)%p) if(b&1) c=(c+a)%p;
    return c;
}
LL ksm(LL a,LL b,LL p)//快速冪 拆分指數 
{
    LL ans=1;
    for(;b;b>>=1,a=mul(a,a,p)) if(b&1) ans=mul(ans,a,p);
    return ans;
}
LL cal(LL A,LL B)
{
    LL x=phl(B),y=x;
    for(int i=2;(LL)i*i<=x;++i)
    if(x%i==0)//約分 
    {
        while(!(y%i)&&ksm(A,y/i,B)==1)y/=i; 
        do x/=i;while(x%i==0);
    }
    if(x>1&&ksm(A,y/x,B)==1)y/=x;//求迴圈節 
    return y;
}
int main()
{
    t=read();
    while(t--)
    {
        A=read();B=read();K=read();
        LL d=gcd(A,B);A/=d;B/=d;//約分 
        ans1=0;
        while(1)
        {
            d=gcd(B,K);
            if(d==1) break;
            B/=d;
            ans1++;//求出混迴圈長度 
        }
        write(ans1);putchar(32);if(B==1) putchar(48);else write(cal(K,B));
        putchar(10);
    }
    return 0;
}