洛谷 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;
}

浙公网安备 33010602011771号