Luogu P7360 「JZOI-1」红包

题目描述

https://www.luogu.com.cn/problem/P7360

简要题意:求 $\prod_{i_1=1}^{n}\prod_{i_2=1}^n\cdots\prod_{i_k=1}^n[i_1,i_2,\cdots,i_k]\bmod 998244353$​​

$n\le 10^6,k\le 10^{100},T=1000$​

Solution

我们考虑单独算每个质数 $p$ 的贡献

我们注意到 $lcm=p^t$​ 太难计算,考虑换成 $p^t|lcm$ 的方式来计算

对于一个 $lcm=p^t$ 的 $k$ 元组,我们考虑分别算 $t$ 次贡献,每次贡献为 $p$​,那么我们可以这样计算贡献,令 $f_i(p)$ 表示 $p^i|[i_1,i_2,\cdots,i_k]$ 的 $k$ 元组个数,这样一个 $p$ 的贡献就是 $p^{\sum_{i=1}^{\log_pn}f_i(p)}$

容易得到 $f_i(p)=n^k-(n-\lfloor\frac{n}{p^i}\rfloor)^k$​, 这个整除启示我们进行数论分块

我们可以预处理出前缀 $i$ 的 $p^t$ 的乘积,然后就可以直接数论分块,另外对于 $k$ 我们直接对 $\varphi(\varphi(998244353))$ 取模即可

预处理 $O(n)$​,单次询问 $O(\sqrt n\log n)$​

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <iostream>
#include <cstring>
#include <vector>
#define maxn 1000010
#define ll long long
using namespace std;

const int p = 998244353;
const int pp = 998244352;
const int ppp = 402653184;

ll pow_mod(ll x, ll n, int p = 998244353) {
ll s = 1;
for (; n; n >>= 1, x = x * x % p)
if (n & 1) s = s * x % p;
return s;
}

int pri[maxn], cnt; bool isp[maxn]; ll mul[maxn], inv[maxn];
void init_isp(int n) {
mul[0] = mul[1] = inv[0] = inv[1] = 1;
for (int i = 2; i <= n; ++i) {
if (!isp[i]) pri[++cnt] = i, mul[i] = i, inv[i] = pow_mod(i, p - 2);
for (int j = 1; j <= cnt && i * pri[j] <= n; ++j) {
isp[i * pri[j]] = 1;
if (i % pri[j] == 0) {
mul[i * pri[j]] = mul[i];
inv[i * pri[j]] = inv[i];
break;
} mul[i * pri[j]] = inv[i * pri[j]] = 1;
}
}
for (int i = 1; i <= n; ++i) mul[i] = mul[i] * mul[i - 1] % p, inv[i] = inv[i] * inv[i - 1] % p;
}

int n; ll k;
char s[maxn];

void work() {
cin >> n >> s + 1; k = 0;
int m = strlen(s + 1); bool flag = 0;
for (int i = 1; i <= m; ++i) {
k = k * 10 + s[i] - '0';
if (k >= ppp) flag = 1, k %= ppp;
} k += flag * ppp; ll ans = 1, nk = pow_mod(n, k, pp);
for (int l = 1, r, i = 1; l <= n; l = r + 1) {
r = n / (n / l);
ll t = nk - pow_mod(n - n / l, k, pp) + pp;
ans = ans * pow_mod(mul[r] * inv[l - 1] % p, t) % p;
} cout << ans << "\n";
}

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);

int T; cin >> T; init_isp(1000000);
while (T--) work();
return 0;
}