将题解码风统一并加上注释。
查看原帖
将题解码风统一并加上注释。
559847
Ferm_Tawn楼主2023/12/20 21:35

兔队:

#include <cstdio>

// 宏定义,用于简化循环语句
#define F(i, a, b) for (int i = (a); i <= (b); ++i)
#define F2(i, a, b) for (int i = (a); i < (b); ++i)

// 定义最大范围
const int MAXN = 1e7 + 1;

// 全局变量声明
int T, Mod, n, m;
int primes[MAXN], pnum = 0;
bool isn_prime[MAXN];
int pi[MAXN], inv[MAXN];
int in[MAXN], fct[MAXN];
int pos[MAXN];

// 初始化函数,进行素数筛选、计算欧拉函数和阶乘
void init() {
	// 素数筛选
	isn_prime[0] = isn_prime[1] = true;
	F(i, 2, MAXN - 1) {
		if (!isn_prime[i]) {
			primes[++pnum] = i;
			// 将 i 的倍数标记为非素数
			for (int j = i * 2; j < MAXN; j += i) {
				isn_prime[j] = true;
			}
		}
	}

	// 计算逆元,用于后续计算
	inv[1] = 1;
	F(i, 2, Mod - 1)
	inv[i] = 1ll * (Mod - Mod / i) * inv[Mod % i] % Mod;

	// 计算 pi 函数值,pi[i] 表示不超过 i 的数中与 i 互质的数的个数
	pi[0] = 1;
	F(i, 1, pnum)
	pi[i] = 1ll * pi[i - 1] * (primes[i] - 1) % Mod;

	// 计算逆元的累积值
	in[0] = 1;
	F(i, 1, pnum)
	in[i] = (primes[i] != Mod) ? 1ll * in[i - 1] * inv[primes[i] % Mod] % Mod : in[i - 1];

	// 计算阶乘的累积值
	fct[0] = 1;
	F(i, 1, MAXN - 1)
	fct[i] = (i != Mod) ? 1ll * fct[i - 1] * i % Mod : fct[i - 1];

	// 计算小于等于 i 的质数的个数
	F(i, 2, MAXN - 1)
	pos[i] = isn_prime[i] ? pos[i - 1] : pos[i - 1] + 1;
}

int main() {
	// 读取测试用例数和模数
	scanf("%d%d", &T, &Mod);
	// 初始化数据
	init();

	// 处理每个测试用例
	while (T--) {
		// 读取 N 和 M
		scanf("%d%d", &n, &m);
		// 判断特殊情况
		if (n >= Mod && m < Mod)
			puts("0");
		else
			// 计算 [1, N!] 中与 M! 互质的数的数量
			printf("%d\n", 1ll * fct[n] * pi[pos[m]] % Mod * in[pos[m]] % Mod);
	}

	return 0;
}

言啄:

#include <cstdio>
#include <algorithm>

// 读取整数
inline int in();
// 输出整数
inline void wr(int);

// 最大范围定义
const int N = (int)1e7 + 5, M = (int)3e6 + 5;
// 存储素数
int p[M], fac[N], p1[M], p2[M];
// 判断素数数组
bool vis[N];

// 素数筛选函数
inline void prime();
// 快速幂取模函数
inline int quick_mod(int, int, int);

int main(int argc, char **argv) {
	// 进行素数筛选
	prime();
	// 读取测试用例数和模数
	register int T = in(), R = in();
	// 预处理阶乘数组
	fac[0] = 1;
	for (register int i = 1; i < N; ++i)
		if (i != R)
			fac[i] = fac[i - 1] * 1ll * i % R;
		else
			fac[i] = fac[i - 1];
	// 特判:约分!
	p1[1] = (p[1] - 1) % R;
	p2[1] = p[1];
	// 计算 p1 和 p2 数组
	for (register int i = 2; i <= p[0]; ++i)
		p1[i] = p1[i - 1] * 1ll * (p[i] - 1) % R, p2[i] = p[i];
	// 将 p 数组中的元素进行逆元处理
	for (register int i = 1; i <= p[0]; ++i)
		if (p[i] != R)
			p[i] = quick_mod(p[i], R - 2, R);
	// 计算 p 数组的累积值
	for (register int i = 2; i <= p[0]; ++i)
		if (p[i] != R)
			p[i] = p[i] * 1ll * p[i - 1] % R;
		else
			p[i] = p[i - 1];
	// 处理每个测试用例
	while (T--) {
		// 读取 N 和 M
		register int n = in(), m = in();
		// 判断特殊情况
		if (m < R && R <= n) {
			puts("0");
			continue;
		}
		// 在 p2 数组中查找小于等于 m 的最大素数的索引
		register int id = std::upper_bound(p2 + 1, p2 + 1 + p[0], m) - (p2 + 1);
		// 根据 id 值判断输出结果
		if (id < 1)
			wr(fac[n]), putchar('\n');
		else
			wr(fac[n] * 1ll * p1[id] % R * 1ll * p[id] % R), putchar('\n');
	}
}

// 快速幂取模函数
inline int quick_mod(int a, int b, int c) {
	register int s = 1;
	while (b) {
		if (b & 1) s = (s * 1ll * a) % c;
		a = (a * 1ll * a) % c;
		b >>= 1;
	}
	return s;
}

// 素数筛选函数
inline void prime() {
	for (register int i = 2; i < N; ++i)
		if (!vis[i]) {
			p[++p[0]] = i;
			if (i * 1ll * i >= N) continue;
			for (register int j = i * i; j < N; j += i)
				vis[j] = 1;
		}
}

// 读取整数函数
inline int in() {
	register char c = getchar();
	register int x = 0, f = 1;
	// 处理负号
	for (; c < '0' || c > '9'; c = getchar())
		if (c == '-') f = -1;
	// 读取数字
	for (; c >= '0' && c <= '9'; c = getchar())
		x = (x << 1) + (x << 3) + (c & 15);
	return x * f;
}

// 输出整数函数
inline void wr(int x) {
	// 处理负号
	if (x < 0) putchar('-'), x = -x;
	// 递归输出
	if (x / 10) wr(x / 10);
	putchar(x % 10 + '0');
}

prean:

#include <cstdio>
#include <cstdint>
#include <algorithm>

// 读取整数
typedef __uint128_t L;
typedef unsigned long long ull;

// 最大范围定义
const int M = 1e7 + 5;

// 全局变量声明
int T, P, mx, top, n[10005], m[10005], pri[M], phi[M], fac[M], ifac[M];
bool zhi[M];

// 快速幂取模结构体定义
struct FastMod {
	ull b, m;
	FastMod(ull b) : b(b), m(ull((L(1) << 64) / b)) {}
	friend inline ull operator%(const ull &a, const FastMod &mod) {
		ull q = (L(mod.m) * a) >> 64;
		ull r = a - q * mod.b;
		return r >= mod.b ? r - mod.b : r;
	}
} mod(2);

// 主函数
signed main() {
	// 变量声明
	register int i, j, x;
	// 读取测试用例数和模数
	scanf("%d%d", &T, &P);
	// 初始化数组
	phi[1] = fac[1] = ifac[1] = 1;
	mod = FastMod(ull(P));

	// 读取测试用例中的 n 和 m,同时记录最大值
	for (i = 1; i <= T; ++i)
		scanf("%d%d", n + i, m + i), mx = n[i] > mx ? n[i] : mx, mx = m[i] > mx ? m[i] : mx;

	// 素数筛选
	for (i = 2; i <= mx; ++i) {
		if (!zhi[i])
			pri[++top] = i, phi[i] = 1;
		for (j = 1; j <= top && (x = i * pri[j]) <= M; ++j) {
			zhi[x] = true;
			if (!(i % pri[j]))
				break;
		}
		phi[i] = i - phi[i];
	}

	// 计算 fac 和 ifac 数组
	for (i = 2; i <= mx; ++i) {
		if (i ^ P)
			fac[i] = 1ull * fac[i - 1] * i % mod, ifac[i] = 1ull * (P - P / i) * ifac[P % i] % mod;
		else
			fac[i] = fac[i - 1], ifac[i] = 1;
	}

	// 计算欧拉函数(phi)和逆元(ifac)数组
	for (i = 2; i <= mx; ++i)
		phi[i] = 1ull * phi[i - 1] * phi[i] % mod, ifac[i] = 1ull * ifac[i - 1] * ifac[i] % mod;

	// 处理每个测试用例并输出结果
	for (i = 1; i <= T; ++i)
		printf("%d\n", n[i] - n[i] % P == m[i] - m[i] % P ? 1ull * fac[n[i]] * ifac[m[i]] % mod * phi[m[i]] % mod : 0);
}

yhgalaxy:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdlib>
using namespace std;

#define Rep(i, l, r) for (int i = (l); i <= (r); ++i)
#define RepD(i, r, l) for (int i = (r); i >= (l); --i)
#define RepG(i, x) for (int i = hd[x]; i; i = e[i].nxt)

typedef long long ll;

const int N = 10000005;

bool np[N]; // 用于素数筛选的标记数组
int mod, n, m, fac[N], phi[N], fac0[N], phi0[N];

// 快速幂取模
ll power(ll x, int n) {
    ll s = 1;
    while (n) {
        if (n & 1)
            (s *= x) %= mod;
        (x *= x) %= mod, n >>= 1;
    }
    return s;
}

int main() {
    int T, lim = 1e7;
    scanf("%d%d", &T, &mod);

    // 筛素数
    np[1] = 1;
    Rep(i, 2, lim)
        if (!np[i])
            for (int j = 2 * i; j <= lim; j += i)
                np[j] = 1;

    fac[0] = phi[0] = 1, fac0[0] = phi0[0] = 0;

    // 计算阶乘和欧拉函数的幂因子
    Rep(i, 1, lim) {
        int x = i, k = 0;

        // 分解质因数,统计幂因子
        while (x % mod == 0) x /= mod, ++k;

        fac[i] = 1ll * fac[i - 1] * x % mod, fac0[i] = fac0[i - 1] + k;

        // 对于素数,欧拉函数为 p - 1,对于合数,欧拉函数为 (p - 1) * p^(k-1),其中 p 为质因数
        x = (np[i] ? i : i - 1), k = 0;
        while (x % mod == 0) x /= mod, ++k;
        phi[i] = 1ll * phi[i - 1] * x % mod, phi0[i] = phi0[i - 1] + k;
    }

    while (T--) {
        scanf("%d%d", &n, &m);
        ll ans = 1ll * fac[n] * phi[m] % mod * power(fac[m], mod - 2) % mod;

        // 特判,如果幂因子不一致则答案为0
        if (fac0[n] + phi0[m] - fac0[m])
            ans = 0;

        printf("%lld\n", ans);
    }

    return 0;
}

2023/12/20 21:35
加载中...