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

【YBTOJ】【Luogu P2480】[SDOI2010]古代豬文

題目連結:

連結

題目大意:

求:

\[m^{\sum_{d|n}C_{n}^{d}}\bmod 999911659 \]

正文:

這種指數一坨式子外面還套個模的一般考慮尤拉定理的推論或擴充套件尤拉定理。這個用擴充套件尤拉定理明顯搞不了,就考慮用尤拉定理的推論。

\[m^{\sum_{d|n}C_{n}^{d}}\equiv m^{\sum_{d|n}C_{n}^{d}\bmod999911658}\pmod{999911659} \]

還是難搞啊這指數一坨。但是我們發現裡面有個組合數,這提示了我們可以 Lucas 定理優化,但是這裡面的這個模數這麼大一坨,還不如不用,所以考慮拆這個模數。在嘗試的過程中你可能會試著將 \(999911658\)

分解質因數,分成了 \(2,3,4679,35617\) 四個質數。這麼小,這麼少,滿足了我們利用 Lucas。但是怎麼將它們重新拼起來才是關鍵。因為只有四個,很少,所以可以考慮用中國剩餘定理:

\[\left\{\begin{matrix} x\equiv a_1&\quad\pmod{2}\\ x\equiv a_2&\quad\pmod{3}\\ x\equiv a_3&\quad\pmod{4679}\\ x\equiv a_4&\quad\pmod{35617} \end{matrix}\right.\]

其中 \(a_i\) 就是要利用 Lucas 求出來的 \(\sum_{d|n}C_{n}^{d}\)

模各質數得到的數。那麼最後我們通過 CRT 求得 \(x\),代入回原式: \(m^x\)

程式碼:

ll M = 999911659ll, ans;
ll m_[5] = {0, 2ll, 3ll, 4679ll, 35617ll}, a[5];
ll prod[N];

void init(ll p)
{
	prod[0] = 1;
	for (register int i = 1; i <= p + 10; i++)
		prod[i] = (prod[i - 1] * i) % p;
}

ll exgcd(ll a, ll b, ll &x, ll &y)
{
	if(b == 0)
	{
		x = 1, y = 0;
		return a;
	}
	int gcd = exgcd(b, a % b, y, x);
	y -= a / b * x;
	return gcd;
}

ll qpow(ll a, ll b, ll p)
{
    a %= p;
	ll ans = 1;
	for(; b; b >>= 1, a = a * a % p)
		if(b & 1)
			ans = ans * a % p;
    return ans;
}
ll C(ll n, ll m, ll p)
{
    if(m > n)return 0;
    if(n == 0) return 1;
    return ((prod[n] * qpow(prod[m], p - 2, p)) % p * qpow(prod[n - m], p - 2, p) % p);
}

ll Lucas(ll n, ll m, ll p)
{
	if(!m) return 1;
	return C(n % p, m % p, p) * Lucas(n / p, m / p, p) % p;
}

int main()
{
	scanf ("%d%d", &n, &m);
	if (m % M == 0) {puts("0"); return 0;}    // 特判 m 是 999911659 因數
	for (int i = 1; i <= 4; i++)
	{
		init(m_[i]);
		for (int j = 1; j * j <= n; j++)
		{
			if(n % j) continue;
			(a[i] += Lucas(n, j, m_[i])) %= m_[i];
			if(j * j == n) continue;
			(a[i] += Lucas(n, n / j, m_[i])) %= m_[i];
		}
	}
	for (int i = 1; i <= 4; i++)
	{
		ll t = 0, y; 
		exgcd(M / m_[i], m_[i], t, y);
		ans += a[i] * (M / m_[i]) * (t < 0? t + m_[i]: t);
	}
	printf("%lld", qpow(m, ans, M));
    return 0;
}