JZOJ 6572 Lg

神仙数论题(

首先上手推式子,考虑枚举 gcd,有 x1,x2,,xnm(lcmni=1xi)gcdni=1xi=md=1(x1,x2,,xnmd(lcmni=1xi)[gcdni=1xi=1])dddx1,x2,,xnmd[gcdni=1xi=1]

考虑设 f(m)=x1,x2,,xnm(lcmni=1xi)[gcdni=1xi=1]

g(m)=x1,x2,,xnm[gcdni=1xi=1]

x1,x2,,xnm(lcmni=1xi)gcdni=1xi=md=1fd(md)ddg(md)

先考虑 g,设 gd(m)=x1,x2,,xnm[gcdni=1xi=d]

则显然有 gd(m)=g(md)

以及 md=1gd(m)=mn

于是有 g(m)=mnmd=2g(md)

故可以使用类似杜教筛的方式在 O(n3/4) 的时间内求出所需的 g 值。

考虑 f,设 fd(m)=x1,x2,,xnm(lcmni=1xi)[gcdni=1xi=d]

则显然有 fd(m)=f(md)dg(md)

以及 md=1fd(m)=x1,x2,,xnmlcmni=1xi

此时考虑设 h(m)=x1,x2,,xnmlcmni=1xi

则有 f(m)=h(m)(md=2f(md)dg(md))1

考虑如何求 h
注意 lcm 和 gcd 的本质:对所有数的每个质因子的指数取 max / min 并乘起来。
注意到,此题中同为乘,那么可以考虑对所有质因子同时做 min-max 容斥。
h(m)=x1,x2,,xnmTS(gcdiTxi)(1)|T|+1 (S=[1,n]Z)

考虑枚举 gcd 并计算贡献,设 st(m)=x1,x2,,xnmTS[gcdiTxi=1](1)|T|+1iT[xit]

则有 h(m)=md=1dsm/d(m)

st,d(m)=x1,x2,,xnmTS[gcdiTxi=d](1)|T|+1iT[xit]

显然有 st,d(m)=std(m)

以及 td=1st,d(m)=nk=1(nk)tkmnk(1)k+1

注意到这很像二项式展开的形式,考虑化一化 nk=1(nk)tkmnk(1)k+1=nk=0(nk)tkmnk(1)k+1(n0)t0mn(1)1=mn+nk=0(nk)tkmnk(1)k+1=mnnk=0(nk)tkmnk(1)k=mnnk=0(nk)(t)kmnk=mn(mt)n

st(m)=mn(mt)ntd=2std(m)

f,g,h,s 的总复杂度瓶颈在于 hs —— 相当于使用了数论分块套数论分块套数论分块,而其他部分带快速幂的 log,故复杂度是 O(m7/8+m3/4logn) 的。

然而注意到要求得答案,实际上还需要求出 md=1dd,而其中的 mO(n) 种值。
考虑先求 md=1dmd+1 再除 (m!)m+1
注意到 md=1dmd+1=md=1mi=dd=mi=1id=1d=mi=1i!,所以可以预处理阶乘。

代码:

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
const int N = 1e8;
const int M = 2e5;
const int MX = 450;
const int mod = 998244353;
inline int fpow(int a,int b,int m = mod)
{
int ret = 1;
for(;b;b >>= 1)
(b & 1) && (ret = (long long)ret * a % m),a = (long long)a * a % m;
return ret;
}
int n,m,lim,ans = 1;
int fac[M + 5],ifac[M + 5],prod[M + 5],iprod[M + 5];
int le[MX + 5],ge[MX + 5],tot;
inline int &id(int x)
{
return x <= lim ? le[x] : ge[m / x];
}
int mem_f[2 * MX + 5],mem_g[2 * MX + 5],mem_h[2 * MX + 5],mem_s[2 * MX + 5][2 * MX + 5];
int g(int m)
{
if(~mem_g[id(m)])
return mem_g[id(m)];
int ret = fpow(m,n,mod - 1);
for(register int l = 2,r;l <= m;l = r + 1)
{
r = m / (m / l);
ret = (ret - (long long)(r - l + 1) * g(m / l) % (mod - 1) + mod - 1) % (mod - 1);
}
return mem_g[id(m)] = ret;
}
int s(int t,int m)
{
if(t > m)
return 0;
if(~mem_s[id(t)][id(m)])
return mem_s[id(t)][id(m)];
int ret = (fpow(m,n,mod - 1) - fpow(m - t,n,mod - 1) + mod - 1) % (mod - 1);
for(register int l = 2,r;l <= t;l = r + 1)
{
r = t / (t / l);
ret = (ret - (long long)(r - l + 1) * s(t / l,m) % (mod - 1) + mod - 1) % (mod - 1);
}
return mem_s[id(t)][id(m)] = ret;
}
int h(int m)
{
if(~mem_h[id(m)])
return mem_h[id(m)];
int ret = 1;
for(register int l = 1,r;l <= m;l = r + 1)
{
r = m / (m / l);
ret = (long long)ret * fpow((long long)fac[r] * ifac[l - 1] % mod,s(m / l,m)) % mod;
}
return mem_h[id(m)] = ret;
}
int f(int m)
{
if(~mem_f[id(m)])
return mem_f[id(m)];
int ret = 1;
for(register int l = 2,r;l <= m;l = r + 1)
{
r = m / (m / l);
ret = (long long)ret * fpow(f(m / l),r - l + 1) % mod * fpow((long long)fac[r] * ifac[l - 1] % mod,g(m / l)) % mod;
}
ret = (long long)h(m) * fpow(ret,mod - 2) % mod;
return mem_f[id(m)] = ret;
}
int main()
{
freopen("lg.in","r",stdin),freopen("lg.out","w",stdout);
memset(mem_f,-1,sizeof mem_f),memset(mem_g,-1,sizeof mem_g),memset(mem_h,-1,sizeof mem_h),memset(mem_s,-1,sizeof mem_s);
scanf("%d%d",&n,&m),fac[0] = prod[0] = 1,lim = sqrt(m);
for(register int i = 1;i <= m;++i)
fac[i] = (long long)fac[i - 1] * i % mod,
prod[i] = (long long)prod[i - 1] * fac[i] % mod;
ifac[m] = fpow(fac[m],mod - 2),
iprod[m] = fpow(prod[m],mod - 2);
for(register int i = m;i;--i)
ifac[i - 1] = (long long)ifac[i] * i % mod,
iprod[i - 1] = (long long)iprod[i] * fac[i] % mod;
for(register int l = 1,r;l <= m;l = r + 1)
{
r = m / (m / l);
id(m / l) = ++tot;
}
for(register int l = 1,r;l <= m;l = r + 1)
{
r = m / (m / l);
ans = (long long)ans * fpow(f(m / l),(long long)(l + r) * (r - l + 1) / 2 % (mod - 1)) % mod * fpow((long long)fpow(fac[r],r + 1) * iprod[r] % mod * fpow(ifac[l - 1],l) % mod * prod[l - 1] % mod,g(m / l)) % mod;
}
printf("%d\n",ans);
}

Related Issues not found

Please contact @Alpha1022 to initialize the comment