【題解】古代豬文 [SDOI2010] [BZOJ1951] [P2480]

【題解】古代豬文 [SDOI2010] [BZOJ1951] [P2480]


在那山的那邊海的那邊有一羣小肥豬。他們活潑又聰明,他們調皮又靈敏。他們自由自在生活在那綠色的大草坪,他們善良勇敢相互都關心……」——選自豬王國民歌


【題目描述】

$($僅供觀賞$)$測試

豬王國的文明源遠流長,博大精深。ui

$iPig$在大肥豬學校圖書館中查閱資料,得知遠古時期豬文文字總個數爲$N$。固然,一種語言若是字數不少,字典也相應會很大。當時的豬王國國王考慮到若是修一本字典,規模有可能遠遠超過康熙字典,花費的豬力、物力將難以估量。故考慮再三沒有進行這一項勞豬傷財之舉。固然,豬王國的文字後來隨着歷史變遷逐漸進行了簡化,去掉了一些不經常使用的字。spa

$iPig$打算研究古時某個朝代的豬文文字。根據相關文獻記載,那個朝代流傳的豬文文字剛好爲遠古時期的$k$分之一,其中$k$是$N$的一個正約數(能夠是$1$和$N$)。不過具體是哪$k$分之一,以及$k$是多少,因爲歷史過於久遠,已經無從考證了。code

$iPig$以爲只要符合文獻,每一種能整除$N$的$k$都是有可能的。他打算考慮到全部可能的k。顯然當$k$等於某個定值時,該朝的豬文文字個數爲$N / k$。然而從$N$個文字中保留下$N / k$個的狀況也是至關多的。$iPig$預計,若是全部可能的k的全部狀況數加起來爲$P$的話,那麼他研究古代文字的代價將會是$G$的$P$次方。get

如今他想知道豬王國研究古代文字的代價是多少。因爲$iPig$以爲這個數字多是天文數字,因此你只須要告訴他答案除以$999911659$的餘數就能夠了。it

【真正的題目描述(人話)】

給定 $n$ 和 $G$ $,$ 求 $:$ $G^{\sum_{d|n}C_n^d}\bmod 999911659$io

【數據規模】ast

$10%$ $1 \leqslant N \leqslant 50$class

$20%$ $1 \leqslant N \leqslant 1000$gc

$40%$ $1 \leqslant N \leqslant 100000$

$100%$ $1 \leqslant N \leqslant 1000000000,1 \leqslant G \leqslant 1000000000$


【分析】

看到上面這個式子,很容易想到暴力解法:枚舉 $n$ 的全部正約數 $d$,分別求出 $C_n^d$ 並累加答案,最後對 $999911659$ 取模,若是你的目的不是 $pian$ $fen$ 而是 $AC$,而且甘願屈服於 $TLE$,$MLE$,$RE$ 的統治,那麼就大膽的去嘗試吧!

【正解】

$【Key$ $1】$:歐拉定理的推論

(什麼?你說你不知道歐拉定理?(O__O "…))

公式:$a^b \equiv a^{b\bmod \varphi(P)}(\bmod P)$ $,$ $gcd(a,P)=1$

在本題中 $P=999911659$ 是一個質數(不要問我是怎麼知道的),因此對任意 $a$ 均知足 $gcd(a,P)=1$,且有 $\varphi(P)=P-1$。

根據公式可得 $G^{\sum_{d|n} C_n^d}=G^{\sum_{d|n}C_n^d\bmod 999911658}(\bmod 999911659)$

所以本題關鍵是計算 $\sum_{d|n}C_n^d\bmod 999911658$

$【Key$ $2】$: $Lucas$ 定理

*公式: $C_n^m=C_{n\bmod P}^{m\bmod P}C_{n/P}^{m/P}(\bmod P)$

求組合數並要求取模,一看就知道要用 $Lucas$ 定理,這裏很少說。

可是...... 模數不爲質數而且數據規模簡直無敵,仍然會被 $TLE,MLE,RE$摁在地上摩擦。 因而咱們須要將這個大巨無霸問題分解成小蒟蒻問題。

$【Key$ $3】$:$Square$ $Free$ $Number$

對 $999911658$ 分解質因數,獲得 $999911658=234679*35617$ ,它的全部質因子的指數都爲 $1$ ,這一類數被稱做 $Square$ $Free$ $Number$ 。 $Q:$ 這樣作有什麼用呢? $A:$ 立刻就會提到。。。

$【Key$ $4】$:$CRT($中國剩餘定理$)$

首先用 $Lucas$ 定理分別求出 $\sum_{d|n}C_n^d$ 對 $2,3,4679,35617$ 這四個質數取模後的值,記爲 $a_1,a_2,a_3,a_4$ ,而後用中國剩餘定理解一個線性同餘方程組:

$\begin{cases}x\bmod 2=a_1\x\bmod 3=a_2\x\bmod 4679=a_3\x\bmod 35617=a_4\end{cases}$

因而咱們就獲得了 $\sum_{d|n}C_n^d\bmod 999911658$ 的一個最小非負整數解 $x$,最後再用一次快速冪計算 $G^x$就是答案。

$【Code】$
#pragma GCC optimize(3,"Ofast","inline")
#pragma GCC optimize(2)
#include<cstdio>
#define LL long long
#define Re register LL
const int PP=35617,P=999911658;
LL x,y,i,j,n,G,fu,ans,a[5],jc[PP+3]={1},mod[5]={0,2,3,4679,35617};char c;
inline void in(Re &x){//【快讀】本身動手,豐衣足食 
    fu=x=0;c=getchar();
    while(c<'0'||c>'9')fu|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=fu?-x:x;
}
inline LL mi(Re x,Re k,Re P){//【快速冪】若是你非要寫龜速乘我也攔不住你 
    Re s=1;
    while(k){
        if(k&1)(s*=x)%=P;
        (x*=x)%=P,k>>=1;
    }
    return s;
}
inline LL Lucas(Re m,Re n,Re p){//【Lucas定理】 
    if(n<m)return 0;
    if(n<p)return jc[n]*mi(jc[m],p-2,p)%p*mi(jc[n-m],p-2,p)%p;
    return Lucas(m/p,n/p,p)*Lucas(m%p,n%p,p)%p;
}
inline void init(Re P){for(Re i=1;i<=P;++i)jc[i]=jc[i-1]*i%P;}//【預處理階乘】
//對於四個模數都要預處理出不一樣的階乘
inline void exgcd(Re &x,Re &y,Re a,Re b){//【擴歐】解線性同餘方程 
    if(!b){x=1,y=0;return;}
    exgcd(x,y,b,a%b);Re X=x;
    x=y,y=X-a/b*y;
}
int main(){
    in(n),in(G);
    if(G%(P+1)==0){printf("0");return 0;}//若是定義P=999911658,注意這裏要加 1 
    //當 G 爲 999911659 的倍數時,直接特判結束 
    for(i=1;i<=4;++i){//【分解質因數】 
        init(mod[i]);//【初始化階乘】 
        for(j=1;j*j<n;++j)
            if(n%j==0)(((a[i]+=Lucas(j,n,mod[i]))%=mod[i])+=Lucas(n/j,n,mod[i]))%=mod[i];
           //累加組合數並取模 
        if(j*j==n)(a[i]+=Lucas(j,n,mod[i]))%=mod[i];
    }
    for(i=1;i<=4;++i){//【中國剩餘定理】跑一遍 CRT 解方程組 
        Re M=P/mod[i];exgcd(x,y,M,mod[i]);
        (x+=mod[i])%=mod[i];(ans+=M*x%P*a[i]%P)%=P;
    }
    printf("%lld",mi(G,(ans+P)%P,P+1));//加 1..... 
}

【題外話】

善良無比的 わたし 提供了本題的測試數據(98u9)哦$QAQ$

相關文章
相關標籤/搜索