Time Limit: 10 Sec
Memory Limit: 256 MB
Description
给定正整数n,m。求
Input
一行两个整数n,m
Output
一个整数,为答案模1000000007后的值
HINT
1<=n,m<=500000,共有3组数据
题目分析
和 洛谷P1829 [国家集训队]Crash的数字表格的推导过程很像
∑ i = 1 n ∑ j = 1 m l c m ( i , j ) g c d ( i , j ) = ∑ i = 1 n ∑ j = 1 m ( i j g c d ( i , j ) ) g c d ( i , j ) \sum_{i=1}^n\sum_{j=1}^mlcm(i,j)^{gcd(i,j)}=\sum_{i=1}^n\sum_{j=1}^m(\frac{ij}{gcd(i,j)})^{gcd(i,j)} i=1∑nj=1∑mlcm(i,j)gcd(i,j)=i=1∑nj=1∑m(gcd(i,j)ij)gcd(i,j)
把gcd提出来枚举
∑ d = 1 m i n ( n , m ) ∑ i = 1 n ∑ j = 1 m ( i j d ) d [ g c d ( i , j ) = d ] \sum_{d=1}^{min(n,m)}\sum_{i=1}^n\sum_{j=1}^m(\frac{ij}{d})^{d}[gcd(i,j)=d] d=1∑min(n,m)i=1∑nj=1∑m(dij)d[gcd(i,j)=d]
若 g c d ( i , j ) = = d gcd(i,j)==d gcd(i,j)==d,则有 g c d ( i / d , j / d ) = 1 gcd(i/d,j/d)=1 gcd(i/d,j/d)=1
∑ d = 1 m i n ( n , m ) ∑ x = 1 ⌊ n d ⌋ ∑ y = 1 ⌊ m d ⌋ ( x d ∗ y d d ) d [ g c d ( x , y ) = 1 ] = ∑ d = 1 m i n ( n , m ) d d ∑ x = 1 ⌊ n d ⌋ ∑ y = 1 ⌊ m d ⌋ ( x y ) d [ g c d ( x , y ) = 1 ] \sum_{d=1}^{min(n,m)}\sum_{x=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{y=1}^{\lfloor\frac{m}{d}\rfloor}(\frac{xd*yd}{d})^{d}[gcd(x,y)=1]=\sum_{d=1}^{min(n,m)}d^d\sum_{x=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{y=1}^{\lfloor\frac{m}{d}\rfloor}(xy)^{d}[gcd(x,y)=1] d=1∑min(n,m)x=1∑⌊dn⌋y=1∑⌊dm⌋(dxd∗yd)d[gcd(x,y)=1]=d=1∑min(n,m)ddx=1∑⌊dn⌋y=1∑⌊dm⌋(xy)d[gcd(x,y)=1]
莫比乌斯反演一下
∑ d = 1 m i n ( n , m ) d d ∑ x = 1 ⌊ n d ⌋ ∑ y = 1 ⌊ m d ⌋ ( x y ) d ∑ z ∣ g c d ( x , y ) μ ( z ) = ∑ d = 1 m i n ( n , m ) d d ∑ x = 1 ⌊ n d ⌋ ∑ y = 1 ⌊ m d ⌋ ( x y ) d ∑ z = 1 g c d ( x , y ) μ ( z ) [ z ∣ g c d ( x , y ) ] \sum_{d=1}^{min(n,m)}d^d\sum_{x=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{y=1}^{\lfloor\frac{m}{d}\rfloor}(xy)^{d}\sum_{z|gcd(x,y)}\mu(z)=\sum_{d=1}^{min(n,m)}d^d\sum_{x=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{y=1}^{\lfloor\frac{m}{d}\rfloor}(xy)^{d}\sum_{z=1}^{gcd(x,y)}\mu(z)[z|gcd(x,y)] d=1∑min(n,m)ddx=1∑⌊dn⌋y=1∑⌊dm⌋(xy)dz∣gcd(x,y)∑μ(z)=d=1∑min(n,m)ddx=1∑⌊dn⌋y=1∑⌊dm⌋(xy)dz=1∑gcd(x,y)μ(z)[z∣gcd(x,y)]
变换一下枚举顺序
∑
d
=
1
m
i
n
(
n
,
m
)
d
d
∑
z
=
1
m
i
n
(
⌊
n
d
⌋
,
⌊
m
d
⌋
)
μ
(
z
)
∑
x
=
1
⌊
n
d
⌋
∑
y
=
1
⌊
m
d
⌋
(
x
y
)
d
[
z
∣
g
c
d
(
x
,
y
)
]
\sum_{d=1}^{min(n,m)}d^d\sum_{z=1}^{min(\lfloor\frac{n}{d}\rfloor,\lfloor\frac{m}{d}\rfloor)}\mu(z)\sum_{x=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{y=1}^{\lfloor\frac{m}{d}\rfloor}(xy)^{d}[z|gcd(x,y)]
d=1∑min(n,m)ddz=1∑min(⌊dn⌋,⌊dm⌋)μ(z)x=1∑⌊dn⌋y=1∑⌊dm⌋(xy)d[z∣gcd(x,y)]
x
,
y
x,y
x,y的枚举替换成枚举
z
z
z的倍数
∑
d
=
1
m
i
n
(
n
,
m
)
d
d
∑
z
=
1
m
i
n
(
⌊
n
d
⌋
,
⌊
m
d
⌋
)
μ
(
z
)
∑
t
1
=
1
⌊
n
d
z
⌋
∑
t
2
=
1
⌊
m
d
z
⌋
(
z
2
t
1
t
2
)
d
=
∑
d
=
1
m
i
n
(
n
,
m
)
d
d
∑
z
=
1
m
i
n
(
⌊
n
d
⌋
,
⌊
m
d
⌋
)
z
2
d
μ
(
z
)
∑
t
1
=
1
⌊
n
d
z
⌋
t
1
d
∑
t
2
=
1
⌊
m
d
z
⌋
t
2
d
\sum_{d=1}^{min(n,m)}d^d\sum_{z=1}^{min(\lfloor\frac{n}{d}\rfloor,\lfloor\frac{m}{d}\rfloor)}\mu(z)\sum_{t_1=1}^{\lfloor\frac{n}{dz}\rfloor}\sum_{t_2=1}^{\lfloor\frac{m}{dz}\rfloor}(z^2t_1t_2)^{d}=\sum_{d=1}^{min(n,m)}d^d\sum_{z=1}^{min(\lfloor\frac{n}{d}\rfloor,\lfloor\frac{m}{d}\rfloor)}z^{2d}\mu(z)\sum_{t_1=1}^{\lfloor\frac{n}{dz}\rfloor}t_1^d\sum_{t_2=1}^{\lfloor\frac{m}{dz}\rfloor}t_2^{d}
d=1∑min(n,m)ddz=1∑min(⌊dn⌋,⌊dm⌋)μ(z)t1=1∑⌊dzn⌋t2=1∑⌊dzm⌋(z2t1t2)d=d=1∑min(n,m)ddz=1∑min(⌊dn⌋,⌊dm⌋)z2dμ(z)t1=1∑⌊dzn⌋t1dt2=1∑⌊dzm⌋t2d
虽然由于每一项几乎都有d次幂不方便维护前缀和
但认真观察发现最后那两个和式每次从上一次d-1次幂继承,只用
O
(
m
/
d
)
O(m/d)
O(m/d)处理
z
2
d
μ
(
z
)
z^{2d}\mu(z)
z2dμ(z)需要
O
(
n
/
d
∗
l
o
g
d
)
O(n/d*logd)
O(n/d∗logd)处理
总复杂度是
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)级的
由于每个测试点只有一组数据,完全可以接受
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long lt;
#define lowbit(x) ((x)&(-x))
int read()
{
int f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return f*x;
}
const int mod=1000000007;
const int maxn=500010;
int T;
int miu[maxn];
int prim[maxn],vis[maxn],cnt;
lt sum[maxn],a[maxn];
lt qpow(lt a,int k)
{
lt res=1;
while(k>0){
if(k&1) res=(res*a)%mod;
a=(a*a)%mod; k>>=1;
}
return res;
}
void Miu(int n)
{
miu[1]=1;
for(int i=2;i<=n;++i)
{
if(!vis[i]) prim[++cnt]=i,miu[i]=-1;
for(int j=1;j<=cnt;++j)
{
if(i*prim[j]>n) break;
vis[i*prim[j]]=1;
if(i%prim[j]==0) break;
else miu[i*prim[j]]=-miu[i];
}
}
}
lt query(int n,int m)
{
lt res=0; if(n>m) swap(n,m);
for(int i=1;i<=m;++i) a[i]=1;
for(int d=1;d<=n;++d)
{
for(lt i=1;i<=m/d;++i)
{
a[i]=a[i]*i%mod;
sum[i]=(sum[i-1]+a[i])%mod;
}
lt tt=0;
for(int j=1;j<=n/d;++j)
{
tt+=(qpow(j,2*d)*miu[j]%mod+mod)%mod * sum[n/(j*d)]%mod * sum[m/(j*d)]%mod;
tt%=mod;
}
res+=qpow(d,d)*tt%mod;
res%=mod;
}
return res;
}
int main()
{
int n=read(),m=read();
Miu(min(n,m));
printf("%lld",query(n,m));
return 0;
}