洛谷 P2155 [SDOI2008] 沙拉公主的困惑

洛谷传送门

思路

\(\gcd\) 的性质(\(\gcd(a,b) = \gcd(a + kb,b)\)\(b\) 为正整数)可知,\(1 \sim N!\) 中与 \(M!\) 互质的数的个数即为:

\[ans = \dfrac{N! \times \phi(M!)}{M!} \]

考虑计算 \(\phi(M!)\)。由欧拉函数计算公式可得,\(\phi(x) = x \times \dfrac{p_1 - 1}{p_1} \times \dfrac{p_2 - 1}{p_2} \times ... \times \dfrac{p_k - 1}{p_k}\),其中 \(p_1,p_2,...,p_k\)\(x\) 的质因子。那么 \(\phi(M!)\) 即为 \(\prod\limits_{i=1}^M i \times \dfrac{p_1 - 1}{p_1} \times \dfrac{p_2 - 1}{p_2} \times ... \times \dfrac{p_k - 1}{p_k}\),其中 \(p_1,p_2,...,p_k\)\(\le M\) 的质数。

化简后即得:\(\phi(M!) = \prod\limits_{i=1}^M i - \operatorname{isprime}(i)\)

有个小细节:题目没有给模数 \(R\) 的范围,因此有可能 \(R|M!\),逆元计算会出错。解决办法是将一个数 \(x\) 拆成 \(a \times R^b\),相乘则 \(a\) 相乘,\(b\) 相加,相除则 \(a\) 乘逆元,\(b\) 相减。

代码

code
/*

p_b_p_b txdy
AThousandMoon txdy
AThousandSuns txdy
hxy txdy

*/

#include <bits/stdc++.h>
#define pb push_back
#define fst first
#define scd second

using namespace std;
typedef long long ll;
typedef pair<ll, ll> pii;

const int N = 10000000;
const int maxn = 10000100;

int mod, fac[maxn], facp[maxn], phi[maxn], phip[maxn];
int pr[1000000], tot;
bool vis[maxn];

ll qpow(ll b, ll p) {
	ll res = 1;
	while (p) {
		if (p & 1) {
			res = res * b % mod;
		}
		b = b * b % mod;
		p >>= 1;
	}
	return res;
}

void init() {
	for (int i = 2; i <= N; ++i) {
		if (!vis[i]) {
			pr[++tot] = i;
		}
		for (int j = 1; j <= tot && i * pr[j] <= N; ++j) {
			vis[i * pr[j]] = 1;
			if (i % pr[j] == 0) {
				break;
			}
		}
	}
	fac[1] = phi[1] = 1;
	facp[1] = phip[1] = 0;
	for (int i = 2; i <= N; ++i) {
		ll x = i, p = 0;
		while (x % mod == 0) {
			x /= mod;
			++p;
		}
		fac[i] = 1LL * fac[i - 1] * x % mod;
		facp[i] = facp[i - 1] + p;
		x = i - (!vis[i]);
		p = 0;
		while (x % mod == 0) {
			x /= mod;
			++p;
		}
		phi[i] = 1LL * phi[i - 1] * x % mod;
		phip[i] = phip[i - 1] + p;
	}
}

void solve() {
	int n, m;
	scanf("%d%d", &n, &m);
	if (facp[n] + phip[m] - facp[m] > 0) {
		puts("0");
		return;
	}
	printf("%lld\n", 1LL * fac[n] * phi[m] % mod * qpow(fac[m], mod - 2) % mod);
}

int main() {
	int T = 1;
	scanf("%d%d", &T, &mod);
	init();
	while (T--) {
		solve();
	}
	return 0;
}
posted @ 2022-07-12 11:48  zltzlt  阅读(32)  评论(0)    收藏  举报