题面
Subtask 6(20pts):n ≤ 10^8 ,m ≤ 200000。
分析
有挺多解法,先介绍题解解法:
∏
l
c
m
g
c
d
=
∏
l
c
m
∑
d
∣
x
ϕ
(
d
)
\prod lcm^{gcd}=\prod lcm^{\sum_{d|x}\phi(d)}
∏lcmgcd=∏lcm∑d∣xϕ(d)
然后考虑统计每个d在答案中的贡献:
∏
d
∏
d
∣
x
i
l
c
m
ϕ
(
d
)
\prod_d \prod_{d|xi} lcm^{\phi(d)}
d∏d∣xi∏lcmϕ(d)
我们可以对该问题进一步简化
∏
d
(
∏
x
i
≤
m
/
d
l
c
m
×
d
)
ϕ
(
d
)
\prod_d (\prod_{xi\leq m/d} lcm\times d)^{\phi(d)}
d∏(xi≤m/d∏lcm×d)ϕ(d)
将d从次方中拆出,就得到
∏
d
(
∏
x
i
≤
m
/
d
l
c
m
)
ϕ
(
d
)
×
d
ϕ
(
d
)
(
m
/
d
)
n
\prod_d (\prod_{xi\leq m/d} lcm)^{\phi(d)}\times d^{\phi(d)(m/d)^n}
d∏(xi≤m/d∏lcm)ϕ(d)×dϕ(d)(m/d)n
枚举d之后,前一部分如何计算:拆成每个质数的贡献,
O
(
m
/
d
)
O(m/d)
O(m/d)
不计快速幂的总复杂度
O
(
m
log
m
)
O(m\log m)
O(mlogm)。事实上由于m/d的有效取值只有
m
\sqrt m
m个,因此常数很小。
第二种方法的简述:
考虑先拆lcm中的贡献。枚举一个质数p,求其指数之和。
即
∏
p
,
x
i
p
m
a
x
(
e
)
g
c
d
\prod_{p,xi} p^{max(e)gcd}
p,xi∏pmax(e)gcd
其中max(e)是指xi中p的最大指数。
我们可以枚举p与maxe,然后问题变成了
p
的
指
数
最
大
值
恰
好
为
m
a
x
e
p的指数最大值恰好为maxe
p的指数最大值恰好为maxe的gcd之和。然后由于最大值<=e是好求的,我们对后者做差分就得到了前者。答案也就是
∏
p
,
m
a
x
e
p
m
a
x
e
∑
g
c
d
\prod_{p,maxe}p^{maxe\sum gcd}
∏p,maxepmaxe∑gcd
然后我们的问题就是禁用一些数后的gcd之和。
众所周知
∑
g
c
d
=
∑
∑
d
∣
g
c
d
ϕ
(
d
)
=
∑
d
c
n
t
[
d
]
n
ϕ
(
d
)
\sum gcd=\sum\sum_{d|gcd}\phi(d)=\sum_dcnt[d]^n\phi(d)
∑gcd=∑∑d∣gcdϕ(d)=∑dcnt[d]nϕ(d)
cnt[d]指是d的倍数的能用的数的个数。
从大指数往小指数删除,维护上述式子的值即可。
复杂度为
O
(
质
因
子
个
数
∗
约
数
个
数
)
=
O
(
m
log
m
×
8
)
O(质因子个数*约数个数)=O(m\log m\times 8)
O(质因子个数∗约数个数)=O(mlogm×8)
方法1的代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10,mo=998244353;
int n,m,p[N],is[N],phi[N];
ll ksm(ll x, ll y, ll mo) {
ll ret=1;
for(;y;y>>=1){
if(y&1)ret=ret*x%mo;
x=x*x%mo;
}
return ret;
}
void init(){
int n=2e5;
phi[1]=1;
for(int i=2;i<=n;i++){
if(!is[i])p[++p[0]]=i,phi[i]=i-1;
for(int j=1;p[j]*i<=n;j++){
is[i*p[j]]=1;
if(i%p[j]==0){
phi[i*p[j]]=phi[i]*p[j];
break;
}else phi[i*p[j]]=phi[i]*(p[j]-1);
}
}
}
ll calc(ll m) {
ll ret=1;
for(int i=1;p[i]<=m&&i<=p[0];i++){
ll cnt=0;
for(ll k=1,t=p[i]; t<=m; t*=p[i],k++){
cnt = (cnt + k * (ksm(m-m/(t*p[i]), n, mo-1) - ksm(m-m/t, n, mo-1))) % (mo-1);
}
if (cnt<0)cnt+=mo-1;
ret = ret * ksm(p[i], cnt, mo) % mo;
}
return ret;
}
int main() {
freopen("lg.in","r",stdin);
freopen("lg.out","w",stdout);
init();
cin>>n>>m;
ll ans=1;
int las=-1,v=0;
for(int d=1;d<=m;d++){
if(las==-1||m/d!=las){
las=m/d;
v=calc(m/d);
}
ans = ans * ksm(v,phi[d],mo) %mo * ksm(d,phi[d]*ksm(m/d,n,mo-1),mo) % mo;
}
cout<<ans<<endl;
}