【题目】
原题地址
题目可以转化为给定
N,M
N
,
M
,求
∑Ni=1∑Mj=1|i−j|gcd(i,j)
∑
i
=
1
N
∑
j
=
1
M
|
i
−
j
|
gcd
(
i
,
j
)
【题目分析】
这种题就是反演辣,不过我不是很会,直接搬过来了大佬的blog
【解题思路】
然后后面只和
Nd,Md
N
d
,
M
d
有关的柿子:设
A=min(Nd,Md),B=max(Nd,Md)
A
=
min
(
N
d
,
M
d
)
,
B
=
max
(
N
d
,
M
d
)
于是:
前面的:令
f(n)=∑d|ndμ(d)
f
(
n
)
=
∑
d
|
n
d
μ
(
d
)
,是个积性函数,那么:
当
n
n
为质数,。
当
n
n
的最小质因数只出现一次:
f(n)=f(np)+f(np)∗μ(p)=f(np)f(p)
f
(
n
)
=
f
(
n
p
)
+
f
(
n
p
)
∗
μ
(
p
)
=
f
(
n
p
)
f
(
p
)
出现多次:
f(n)=f(np)+f(np)∗0=f(np)
f
(
n
)
=
f
(
n
p
)
+
f
(
n
p
)
∗
0
=
f
(
n
p
)
询问下底分块即可。
事实上反演的步骤我自己推了出来,但是后面的柿子处理以及积性函数推导不太会,然后就弃疗了。。。
【参考代码】
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=2e6+10;
const int mod1=1e9+7;
const int mod2=1e9+9;
int n,m,cas,prinum,ans1,ans2;
int vis[N],pri[N],f[N][2];
void add(int &x,int y,int mod){(x+=y)%=mod;}
int F(int A,int B,int mod)
{
if(!A || !B) return 0;
if(A>B) swap(A,B);
int c1=1ll*(A-1)*A*(A+1)/3ll%mod;
int c2=1ll*A*B*(B-A)/2ll%mod;
add(c1,c2,mod);
return c1;
}
void init()
{
f[1][0]=f[1][1]=1;
for(int i=2;i<N;++i)
{
if(!vis[i])
{
pri[++prinum]=i;
f[i][0]=mod1-i+1;f[i][1]=mod2-i+1;
}
for(int j=1;j<=prinum && 1ll*i*pri[j]<N;++j)
{
vis[i*pri[j]]=1;
if(i%pri[j])
{
f[i*pri[j]][0]=1ll*f[i][0]*f[pri[j]][0]%mod1;
f[i*pri[j]][1]=1ll*f[i][1]*f[pri[j]][1]%mod2;
}
else
{
f[i*pri[j]][0]=f[i][0];f[i*pri[j]][1]=f[i][1];
break;
}
}
}
for(int i=2;i<N;++i)
add(f[i][0],f[i-1][0],mod1),add(f[i][1],f[i-1][1],mod2);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("BZOJ4018.in","r",stdin);
freopen("BZOJ4018.out","w",stdout);
#endif
init();
scanf("%d",&cas);
while(cas--)
{
scanf("%d%d",&n,&m);ans1=ans2=0;
if(n>m) swap(n,m);
for(int i=1,j;i<=n;i=j+1)
{
j=min(n/(n/i),m/(m/i));
add(ans1,1ll*(f[j][0]-f[i-1][0]+mod1)*F(n/i,m/i,mod1)%mod1,mod1);
add(ans2,1ll*(f[j][1]-f[i-1][1]+mod2)*F(n/i,m/i,mod2)%mod2,mod2);
}
printf("%d %d\n",ans1,ans2);
}
return 0;
}
【总结】
好好学数论0 0