一、题目
二、解法
建议做这道题之前先把 [SDOI 2015]约数个数和 做了,你就会发现有这样一个等价变换:
∑
i
=
1
a
∑
j
=
1
b
∑
k
=
1
c
∑
x
∣
i
∑
y
∣
j
∑
z
∣
k
[
(
x
,
y
)
=
1
]
[
(
y
,
z
)
=
1
]
[
(
x
,
z
)
=
1
]
\sum_{i=1}^a\sum_{j=1}^b\sum_{k=1}^c\sum_{x|i}\sum_{y|j}\sum_{z|k}[(x,y)=1][(y,z)=1][(x,z)=1]
i=1∑aj=1∑bk=1∑cx∣i∑y∣j∑z∣k∑[(x,y)=1][(y,z)=1][(x,z)=1]先枚举
x
,
y
,
z
x,y,z
x,y,z(写还是写作
i
,
j
,
k
i,j,k
i,j,k):
∑
i
=
1
a
∑
j
=
1
b
∑
k
=
1
c
a
i
×
b
j
×
c
k
×
[
(
i
,
j
)
=
1
]
[
(
j
,
k
)
=
1
]
[
(
i
,
k
)
=
1
]
\sum_{i=1}^a\sum_{j=1}^b\sum_{k=1}^c\frac{a}{i}\times\frac{b}{j}\times\frac{c}{k}\times[(i,j)=1][(j,k)=1][(i,k)=1]
i=1∑aj=1∑bk=1∑cia×jb×kc×[(i,j)=1][(j,k)=1][(i,k)=1]然后改变一下枚举顺序:
∑
i
=
1
a
∑
j
=
1
b
a
i
×
b
j
×
[
(
i
,
j
)
=
1
]
∑
k
=
1
c
c
k
×
[
(
i
j
,
k
)
=
1
]
\sum_{i=1}^a\sum_{j=1}^b\frac{a}{i}\times\frac{b}{j}\times[(i,j)=1]\sum_{k=1}^c\frac{c}{k}\times[(ij,k)=1]
i=1∑aj=1∑bia×jb×[(i,j)=1]k=1∑ckc×[(ij,k)=1]时间复杂度
O
(
n
2
log
n
)
O(n^2\log n)
O(n2logn)是允许的,前面不需要变化了,我们反演后面的部分:
f
(
x
)
=
∑
k
=
1
c
c
k
∑
d
∣
(
x
,
k
)
μ
(
d
)
f(x)=\sum_{k=1}^c\frac{c}{k}\sum_{d|(x,k)}\mu(d)
f(x)=k=1∑ckcd∣(x,k)∑μ(d)先枚举
d
d
d:
f
(
x
)
=
∑
d
∣
x
μ
(
d
)
∑
d
∣
k
c
k
f(x)=\sum_{d|x}\mu(d)\sum_{d|k}\frac{c}{k}
f(x)=d∣x∑μ(d)d∣k∑kc我们可以先预处理
∑
d
∣
x
c
k
\sum_{d|x}\frac{c}{k}
∑d∣xkc,然后枚举
d
d
d,就可以算这个柿子了,前面的部分暴力算就行了,时间复杂度
O
(
n
2
log
n
)
O(n^2\log n)
O(n2logn)。
#include <cstdio>
#include <iostream>
using namespace std;
const int N = 2005;
const int M = 4000005;
const int jzm = (1<<30)-1;
int read()
{
int x=0,flag=1;
char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int a,b,c,ans,cnt,p[N],mu[N],vis[N],f[M];
void sieve(int n)
{
mu[1]=1;
for(int i=2;i<=n;i++)
{
if(!vis[i]) p[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt && i*p[j]<=n;j++)
{
vis[i*p[j]]=1;
if(i%p[j]==0) break;
mu[i*p[j]]=-mu[i];
}
}
}
int gcd(int a,int b)
{
return !b?a:gcd(b,a%b);
}
int main()
{
a=read();b=read();c=read();
if(a>b) swap(a,b);
if(a>c) swap(a,c);
if(b>c) swap(b,c);
sieve(c);
for(int i=1;i<=c;i++)
{
int s=0;
for(int j=i;j<=c;j+=i)
s+=c/j;
for(int j=i;j<=a*b;j+=i)
(f[j]+=mu[i]*s)&=jzm;
}
for(int i=1;i<=a;i++)
for(int j=1;j<=b;j++)
if(gcd(i,j)==1)
{
ans+=(1ll*(a/i)*(b/j)*f[i*j])&jzm;
ans&=jzm;
}
printf("%d\n",ans);
}