欢迎大家访问我的老师的OJ———caioj.cn
题面描述
思路
由Zap的结论我们可以知道
我们这题应该求的是
∑
i
s
p
r
i
m
e
(
p
)
∑
i
=
1
min
(
⌊
n
/
p
⌋
,
⌊
m
/
p
⌋
)
μ
(
i
)
∗
⌊
⌊
n
/
p
⌋
/
i
⌋
∗
⌊
⌊
m
/
p
⌋
/
i
⌋
\large\sum_{isprime(p)}\sum_{i=1}^{\min(\left\lfloor n/p\right\rfloor,\left\lfloor m/p\right\rfloor)}\mu(i)*\left\lfloor\\\left\lfloor n/p\right\rfloor/i\right\rfloor*\left\lfloor\\\left\lfloor m/p\right\rfloor/i\right\rfloor
isprime(p)∑i=1∑min(⌊n/p⌋,⌊m/p⌋)μ(i)∗⌊⌊n/p⌋/i⌋∗⌊⌊m/p⌋/i⌋
设
k
=
p
∗
i
k=p*i
k=p∗i,则上式应为:
∑
k
=
1
n
∑
i
s
p
r
i
m
e
(
p
)
并
且
p
∣
k
μ
(
k
p
)
∗
⌊
n
/
k
⌋
∗
⌊
m
/
k
⌋
\large\sum_{k=1}^n\sum_{isprime(p)并且p\mid k}\mu(\frac{k}{p})*\left\lfloor\\ n/k\right\rfloor*\left\lfloor\\ m/k\right\rfloor
k=1∑nisprime(p)并且p∣k∑μ(pk)∗⌊n/k⌋∗⌊m/k⌋
设
f
(
k
)
=
∑
i
s
p
r
i
m
e
(
p
)
并
且
p
∣
k
μ
(
k
p
)
f(k)=\sum_{isprime(p)并且p|k}\mu(\frac{k}{p})
f(k)=∑isprime(p)并且p∣kμ(pk)就有
∑
k
=
1
n
f
(
k
)
∗
⌊
n
/
k
⌋
∗
⌊
m
/
k
⌋
\large\sum_{k=1}^nf(k)*\left\lfloor\\ n/k\right\rfloor*\left\lfloor\\ m/k\right\rfloor
k=1∑nf(k)∗⌊n/k⌋∗⌊m/k⌋
预处理出 f ( k ) f(k) f(k)的前缀和即可。
慢一点的预处理
void g_p()
{
m=0;mu[1]=1;
for(int i=2;i<=inf;i++)
{
if(!v[i])prime[++m]=i,mu[i]=-1;
for(int j=1;j<=m&&i*prime[j]<=inf;j++)
{
v[i*prime[j]]=1;
if(i%prime[j]==0){mu[i*prime[j]]=0;break;}
else{mu[i*prime[j]]=-mu[i];}
}
}
for(int i=1;i<=m;i++)
{
int p=prime[i];
for(int j=1;j*p<=inf;j++)f[j*p]+=mu[j];
}
for(int i=2;i<=inf;i++)f[i]+=f[i-1];
}
快一点的预处理
void g_p()
{
m=0;mu[1]=1;
for(int i=2;i<=inf;i++)
{
if(!v[i])prime[++m]=i,mu[i]=-1,f[i]=1;//f[i]=mu[i/i]
for(int j=1;j<=m&&i*prime[j]<=inf;j++)
{
v[i*prime[j]]=1;
if(i%prime[j]==0){f[i*prime[j]]=mu[i];mu[i*prime[j]]=0;break;}
else{mu[i*prime[j]]=-mu[i];f[i*prime[j]]=-f[i]+mu[i];}
}
}
for(int i=2;i<=inf;i++)f[i]+=f[i-1];
}
稍微解释一下:
f[i*prime[j]]=-f[i]+mu[i]
因为 f ( i ) f(i) f(i)可以类似看作一个 μ \mu μ的集合,现在这个集合中都乘上一个 p r i m e [ j ] prime[j] prime[j],会导致 μ \mu μ的值成为其相反数。
同理 f ( i ∗ p r i m e [ j ] ) f(i*prime[j]) f(i∗prime[j])理应成为 f ( i ) f(i) f(i)的相反数再加上 p r i m e [ j ] prime[j] prime[j]
AC code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#define ll long long
#define gc getchar()
using namespace std;
const int N=1e7+10;
const int M=5e6+10;
const int inf=1e7;
inline void qr(int &x)
{
x=0;int f=1;char c=gc;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc;}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
x*=f;
}
void qw(ll x)
{
if(x/10)qw(x/10);
putchar(x%10+48);
}
int prime[M],m,mu[N];ll f[N];bool v[N];
void g_p()
{
m=0;mu[1]=1;
for(int i=2;i<=inf;i++)
{
if(!v[i])prime[++m]=i,mu[i]=-1,f[i]=1;
for(int j=1;j<=m&&i*prime[j]<=inf;j++)
{
v[i*prime[j]]=1;
if(i%prime[j]==0){f[i*prime[j]]=mu[i];mu[i*prime[j]]=0;break;}
else{mu[i*prime[j]]=-mu[i];f[i*prime[j]]=-f[i]+mu[i];}
}
}
for(int i=2;i<=inf;i++)f[i]+=f[i-1];
}
ll calc(int a,int b)
{
if(a>b)swap(a,b);
ll ans=0;
for(int x=1,gx;x<=a;x=gx+1)
{
gx=min(a/(a/x),b/(b/x));
ans+=(f[gx]-f[x-1])*(a/x)*(b/x);
}
return ans;
}
int main()
{
g_p();
int n;qr(n);
while(n--)
{
int a,b;qr(a),qr(b);
qw(calc(a,b));puts("");
}
return 0;
}