1. 程式人生 > 實用技巧 >P2480 [SDOI2010]古代豬文

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\)

,以及 \(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\)

前置芝士

  1. 中國剩餘定理(求答案)

  2. 尤拉定理拓展

  3. 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));
}  

ENDING