P2480 [SDOI2010]古代豬文
題目背景
“在那山的那邊海的那邊有一群小肥豬。他們活潑又聰明,他們調皮又靈敏。他們自由自在生活在那綠色的大草坪,他們善良勇敢相互都關心……”
——選自豬王國民歌
很久很久以前,在山的那邊海的那邊的某片風水寶地曾經存在過一個豬王國。豬王國地理位置偏僻,實施的是適應當時社會的自給自足的莊園經濟,
很少與外界聯絡,商貿活動就更少了。因此也很少有其他動物知道這樣一個王國。
豬王國雖然不大,但是土地肥沃,屋舍儼然。如果一定要拿什麼與之相比的話,那就只能是東晉陶淵明筆下的大家想象中的桃花源了。豬王勤政愛民
,豬民安居樂業,鄰里和睦相處,國家秩序井然,經濟欣欣向榮,社會和諧穩定。和諧的社會帶給豬民們對工作火紅的熱情和對未來的粉色的憧憬。
小豬iPig是豬王國的一個很普通的公民。小豬今年10歲了,在大肥豬學校上小學三年級。和大多數豬一樣,他不是很聰明,因此經常遇到很多或者
稀奇古怪或者旁人看來輕而易舉的事情令他大傷腦筋。小豬後來參加了全豬資訊學奧林匹克競賽(Pig Olympiad in Informatics, POI),取得了
不錯的名次,最終保送進入了豬王國大學(Pig Kingdom University, PKU)深造。
現在的小豬已經能用計算機解決簡單的問題了,比如能用P++語言編寫程式計算出A + B的值。這個“成就”已經成為了他津津樂道的話題。
當然,不明真相的同學們也開始對他刮目相看啦~
小豬的故事就將從此展開,伴隨大家兩天時間,希望大家能夠喜歡小豬。
題目描述
豬王國的文明源遠流長,博大精深。
iPig 在大肥豬學校圖書館中查閱資料,得知遠古時期豬文文字總個數為 \(n\) 。當然,一種語言如果字數很多,字典也相應會很大。
當時的豬王國國王考慮到如果修一本字典,規模有可能遠遠超過康熙字典,花費的豬力、物力將難以估量。故考慮再三沒有進行這一項勞豬傷財之舉
。當然,豬王國的文字後來隨著歷史變遷逐漸進行了簡化,去掉了一些不常用的字。
iPig 打算研究古時某個朝代的豬文文字。根據相關文獻記載,那個朝代流傳的豬文文字恰好為遠古時期的 \(1\over k\),
其中 \(k\) 是 \(n\) 的一個正約數(可以是 \(1\) 或 \(n\))。不過具體是哪 \(1\over k\)
iPig 覺得只要符合文獻,每一種 \(k∣n\) 都是有可能的。他打算考慮到所有可能的 \(k\)。顯然當 \(k\) 等於某個定值時,
該朝的豬文文字個數為 \(n \over k\)。然而從 \(n\) 個文字中保留下 \(n\over k\) 個的情況也是相當多的。iPig 預計,
如果所有可能的 \(k\) 的所有情況數加起來為 \(p\) 的話,那麼他研究古代文字的代價將會是 \(g^p\)。
現在他想知道豬王國研究古代文字的代價是多少。由於 iPig 覺得這個數字可能是天文數字,
所以你只需要告訴他答案除以 \(999911659\) 的餘數就可以了。
輸入格式
一行兩個正整數 n,g。
輸出格式
輸出一行一個整數表示答案。
輸入輸出樣例
輸入 #1
4 2
輸出 #1
2048
資料範圍與提示
對於 \(10\%\) 的資料 \(1\le n \le 50\);
對於 \(20\%\) 的資料,\(1\le n \le 1000\);
對於 \(40\%\) 的資料,\(1\le n \le 10^5\);
對於 \(100\%\) 的資料,\(1\le n,g \le 10^9\)。
前置芝士
-
中國剩餘定理(求答案)
-
尤拉定理拓展
-
Lucas定理(求組合數)
一句話題意 \(g^{\sum_{d|n} C_{n}^{d} \bmod 999911659}\)
首先,根據尤拉定理的拓展可得
\(g^{\sum_{d|n} C_{n}^{d}} \bmod 999911659\) = \(g^{\sum_{d|n}C_{n}^{d} \bmod 999911658}\)
這個題關鍵就在於求出\(\sum_{d|n}C_{n}^{d} \bmod 999911658\)這個柿子
看到n的範圍那麼大,只有盧卡斯定理可以解決這種問題。
但模數又不是質數,那怎麼辦呢?
我們可以考慮對 \(999911658\) 進行因數分解 \(999911658 = 2 \times 3 \times 4679 \times 35617\)
發現他的因數都是質數,且指數都為1.
那這麼不就可以用Lucas定理求出組合數了嗎?
最後,我們考慮怎麼統計答案
假設,我們計算出\(\sum_{d|n}C_{n}{d}\) mod 2,3,4679,35617 的結果分別為s1,s2,s3,s4
那麼我們可以得到這樣一組線性方程
\[\left\{ \begin{array}{lrc} x \equiv s1 (\bmod 2) \\ x \equiv s2 (\bmod 3) \\ x \equiv s3 (\bmod 4679) \\ x \equiv s4 (\bmod 35617) \end{array} \right. \]
這樣,我們就可以利用中國剩餘定理求解出最小的解,然後快速冪算出答案就解決了。
除此之外,還要特判一下 g = 999911659 的情況
為毛關於豬的都這麼毒瘤(豬國殺,魔法豬學院,古代豬文)
程式碼
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define LL long long
#define int long long
int mod = 999911658;
int g,n,ans,jz[36000],sum[5];
int p[5] = {0,2,3,4679,35617};
LL ksm(LL a,LL b,LL p)
{
LL res = 1;
for(; b; b >>= 1)
{
if(b & 1) res = res * a % p;
a = a * a % p;
}
return res;
}
LL C(int n,int m,int p)//計算組合數
{
if(n < m) return 0;
return jz[n] % p * ksm(jz[m],p-2,p) % p * ksm(jz[n-m],p-2,p) % p;
}
LL Lucas(int n,int m,int p)//Lucas定理求組合數
{
if(m == 0) return 1;
return C(n%p,m%p,p) * Lucas(n/p,m/p,p) % p;
}
signed main()
{
scanf("%d%d",&n,&g); jz[0] = 1;
if(g == 999911659)//特判一下
{
cout<<0<<endl;
return 0;
}
for(int i = 1; i <= 36000; i++) jz[i] = jz[i-1] * i % mod;//預處理出階乘
for(int i = 1; i * i <= n; i++)//列舉因子
{
for(int j = 1; j <= 4; j++)
{
if(i * i == n)
{
sum[j] = (sum[j] + Lucas(n,i,p[j])) % p[j];//計算出s1,s2,s3,s4
}
else if(n % i == 0)
{
sum[j] = (sum[j] + Lucas(n,i,p[j])) % p[j];
sum[j] = (sum[j] + Lucas(n,n/i,p[j])) % p[j];
}
}
}
for(int i = 1; i <= 4; i++)
{
ans = (ans + sum[i] * (mod/p[i]) % mod * ksm(mod/p[i],p[i]-2,p[i]) % mod) % mod;//中國剩餘定理求解線性同餘方程
}
ans = (ans % mod + mod) % mod; mod++;
printf("%lld\n",ksm(g,ans,mod));
}