BZOJ 1951: [Sdoi2010]古代猪文

要求 \(g^{\sum \limits _{i|n}\binom{n}{i}}\)
欧拉降幂之后就变成求 \(\sum \limits_{i|n}\binom{n}{i} \bmod (M - 1)\)
\(M - 1\) 是个合数,当时对它进行质因数分解后发现它是四个质数的乘积,分别对四个质数进行Lucas定理求组合数,最后再CRT合并一下

#include <bits/stdc++.h>

const int mod[10] = {2, 3, 4679, 35617}, MOD = 999911659, M = 999911658;
int fac[10][36000], inv[10][36000];

int qp(int a, int b, int m = MOD) {
	int ans = 1;
	a %= m;
	for (; b; b >>= 1, a = 1LL * a * a % m) 
		if (b & 1)
			ans = 1LL * ans * a % m;
	return ans % m;
}

int C(int n, int m, int cur) {
	if (n < m) return 0;
	int MOD = mod[cur];
	return 1LL * fac[cur][n] * inv[cur][m] % MOD * inv[cur][n - m] % MOD;
}

int Lucas(int n, int m, int cur) {
	if (n < m) return 0;
	int MOD = mod[cur];
	return m ? 1LL * Lucas(n / MOD, m / MOD, cur) * C(n % MOD, m % MOD, cur) % MOD : 1;
}

int a[4];

int CRT() {
	int ans = 0;
	for (int i = 0; i < 4; i++) {
		int m = M / mod[i];
		int inv_m = qp(m, mod[i] - 2, mod[i]);
		(ans += 1LL * m * inv_m % M * a[i] % M) %= M;
	}
	return ans;
}

int main() {
	for (int i = 0; i < 4; i++) 
		for (int j = fac[i][0] = 1; j < mod[i]; j++)
			fac[i][j] = 1LL * fac[i][j - 1] * j % mod[i];
	for (int i = 0; i < 4; i++) {
		inv[i][mod[i] - 1] = qp(fac[i][mod[i] - 1], mod[i] - 2, mod[i]);
		for (int j = mod[i] - 2; j >= 0; j--)
			inv[i][j] = 1LL * inv[i][j + 1] * (j + 1) % mod[i];
	}
	int n, g;
	scanf("%d%d", &n, &g);
	if (g == MOD) {
		puts("0");
		return 0;
	}
	g %= MOD;
	for (int i = 1; i * i <= n; i++) {
		if (n % i) continue;
		int x = i;
		for (int j = 0; j < 4; j++)
			a[j] = (a[j] + Lucas(n, x, j)) % mod[j];
		if (i * i == n) continue;
		x = n / i;
		for (int j = 0; j < 4; j++)
			a[j] = (a[j] + Lucas(n, x, j)) % mod[j];
	}
	printf("%d\n", qp(g, CRT()));
	return 0;
}
posted @ 2020-02-12 10:58  Mrzdtz220  阅读(123)  评论(0)    收藏  举报