专栏文章

题解:P7360 「JZOI-1」红包

P7360题解参与者 3已保存评论 2

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
2 条
当前快照
1 份
快照标识符
@minyj26c
此快照首次捕获于
2025/12/02 10:26
3 个月前
此快照最后确认于
2025/12/02 10:26
3 个月前
查看原文

前言:

好题啊,可惜各位大佬的莫反,容斥,一堆的式子我都看不懂啊,只看懂了 Corzica 大佬的做法,这里主要是对其做法的补充解释。

思路:

首先考虑对于每个质数 pp,它对答案的贡献:若 lcm\operatorname{lcm} 中含有 pqp^q,总共有 nkn^k 种方案,其中 lcm\operatorname{lcm} 不含 pqp^q 的方案数是 nk(npq)kn^k-(\frac{n}{p^q})^k,相减就是含 lcm\operatorname{lcm} 的方案。对答案的贡献是 pnk(npq)kp^{n^k-(\frac{n}{p^q})^k},为啥底数不是 pqp^q 呢,因为我们已经统计过了 lcm\operatorname{lcm} 含有 pq1,pq2...pp^{q-1},p^{q-2}...p 了,pqp^q 只多了 pp 的贡献,所以底数是 pp
又因为读入的 kk 很大,根据扩展欧拉定理和费马小定理,对于指数上的 nkn^kkkφ(mod1)φ(mod-1) 即可,指数的答案再模 mod1mod-1。这样单次时间是 O(nlogn)O(n\log{n}) 的,对于 npq\frac{n}{p^q},发现可以整除分块,单次时间复杂度降至 O(nlogn)O(\sqrt{n}\log{n}),可以通过。还有别的问题就看代码吧,实现也是比较简单的。
CPP
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 10;
const int mod = 998244353;
const int phi = 402653184;//998244352 的phi值
int n, m, pr[N], cnt, f[N], T;
bool vis[N];
//快速幂
inline int quickpow(int x, int y, int mod) {
	if (y == 1)return x;
	if (y == 0)return 1;
	int g = quickpow(x, y / 2, mod);
	if (y & 1)return g * g % mod * x % mod;
	return g * g % mod;
}
signed main() {
	ios :: sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	//f[i]记录i这个数是不是一个质数的 n 次方,是的话,是哪个质数,可以线性筛预处理
	n = 1e6;
	for (int i = 2; i <= n; i ++) {
		if (!vis[i]) {
			pr[++ cnt] = i;
			f[i] = i;
		}
		for (int j = 1; j <= cnt && i * pr[j] <= n; j ++) {
			vis[pr[j] * i] = 1;
			if (i % pr[j] == 0) {
				f[i * pr[j]] = f[i];
				break;
			}
		}
	}
	f[0] = 1;
	for (int i = 1; i <= n; i ++) {
		if (!f[i])f[i] = 1;
		f[i] = f[i - 1] * f[i] % mod;
	}
	//预处理前缀积
	cin >> T;
	while (T --) {
		cin >> n;
		string s;
		cin >> s;
		m = 0;
		for (int i = 0; i < s.size(); i ++) {
			m = m * 10 + s[i] - '0';
			if (m >= phi) m = m % phi + phi;
		}//读入时将k 模 φ(mod - 1),因为 k 在最后的式子上在指数的指数上
		int all = quickpow(n, m, mod - 1), ans = 1;
		//总是用 n ^ k 去减,可以直接算好
		for (int l = 1; l <= n; l ++) {
			int r = n / (n / l);//整除分块
			if (f[r] != f[l - 1]) {
				//f[r] / f[l - 1] 求 l ~ r 的积
				ans *= quickpow(f[r] * quickpow(f[l - 1], mod - 2, mod) % mod, (all - quickpow(n - n / l, m, mod - 1)/*减去 lcm 中没有 p ^ q 的方案*/ + mod - 1) % (mod - 1), mod);
				ans %= mod;
			}
			l = r;
		}
		cout << ans << '\n';
	}
	return 0;
}

评论

2 条评论,欢迎与作者交流。

正在加载评论...