题目描述
题目解法
我们令
g
(
x
)
g(x)
g(x) 为
x
x
x 的约数和
答案为:
∑
i
=
1
n
∑
j
=
1
m
[
g
[
g
c
d
(
i
,
j
)
]
<
=
a
]
g
[
g
c
d
(
i
,
j
)
]
\sum_{i=1}^{n}\sum_{j=1}^{m}[g[gcd(i,j)]<=a]g[gcd(i,j)]
∑i=1n∑j=1m[g[gcd(i,j)]<=a]g[gcd(i,j)]
按照套路枚举
g
c
d
(
i
,
j
)
gcd(i,j)
gcd(i,j):
∑
d
=
1
m
i
n
(
n
,
m
)
[
g
(
d
)
<
=
a
]
∑
i
′
=
1
⌊
n
d
⌋
∑
j
′
=
1
⌊
m
d
⌋
[
g
c
d
(
i
′
,
j
′
)
=
1
]
g
(
d
)
\sum_{d=1}^{min(n,m)}[g(d)<=a]\sum_{i'=1}^{\left \lfloor \frac{n}{d} \right \rfloor}\sum_{j'=1}^{\left \lfloor \frac{m}{d} \right \rfloor}[gcd(i',j')=1]g(d)
∑d=1min(n,m)[g(d)<=a]∑i′=1⌊dn⌋∑j′=1⌊dm⌋[gcd(i′,j′)=1]g(d)
如果
x
>
1
x>1
x>1,那么
∑
d
∣
x
μ
(
d
)
\sum_{d|x} \mu(d)
∑d∣xμ(d) 为
0
0
0:
∑
d
=
1
m
i
n
(
n
,
m
)
[
g
(
d
)
<
=
a
]
g
[
d
]
∗
∑
i
′
=
1
⌊
n
d
⌋
∑
j
′
=
1
⌊
m
d
⌋
∑
d
′
∣
i
′
且
d
′
∣
j
′
μ
(
d
′
)
\sum_{d=1}^{min(n,m)}[g(d)<=a]g[d]*\sum_{i'=1}^{\left \lfloor \frac{n}{d} \right \rfloor}\sum_{j'=1}^{\left \lfloor \frac{m}{d} \right \rfloor}\sum_{d'|i'且d'|j'}\mu(d')
∑d=1min(n,m)[g(d)<=a]g[d]∗∑i′=1⌊dn⌋∑j′=1⌊dm⌋∑d′∣i′且d′∣j′μ(d′)
交换
i
′
,
j
′
,
d
′
i',j',d'
i′,j′,d′ 的循环顺序:
∑
d
=
1
m
i
n
(
n
,
m
)
[
g
(
d
)
<
=
a
]
g
[
d
]
∗
∑
d
′
=
1
m
i
n
(
⌊
n
d
⌋
,
⌊
m
d
⌋
)
μ
(
d
′
)
⌊
n
d
d
′
⌋
⌊
m
d
d
′
⌋
\sum_{d=1}^{min(n,m)}[g(d)<=a]g[d]*\sum_{d'=1}^{min(\left \lfloor \frac{n}{d} \right \rfloor,\left \lfloor \frac{m}{d} \right \rfloor)}\mu(d')\left \lfloor \frac{n}{dd'} \right \rfloor\left \lfloor \frac{m}{dd'} \right \rfloor
∑d=1min(n,m)[g(d)<=a]g[d]∗∑d′=1min(⌊dn⌋,⌊dm⌋)μ(d′)⌊dd′n⌋⌊dd′m⌋
令
T
=
d
d
′
T=dd'
T=dd′,且先枚举
T
T
T 来交换循环顺序:
∑
T
=
1
m
i
n
(
N
,
M
)
⌊
n
T
⌋
⌊
m
T
⌋
∑
d
∣
T
[
g
(
d
)
<
=
a
]
g
(
d
)
∗
μ
(
T
d
)
\sum_{T=1}^{min(N,M)}\left \lfloor \frac{n}{T} \right \rfloor\left \lfloor \frac{m}{T} \right \rfloor\sum_{d|T}[g(d)<=a]g(d)*\mu(\frac{T}{d})
∑T=1min(N,M)⌊Tn⌋⌊Tm⌋∑d∣T[g(d)<=a]g(d)∗μ(dT)
我么令
h
(
T
)
h(T)
h(T) 为
∑
d
∣
T
[
g
(
d
)
<
=
a
]
g
(
d
)
∗
μ
(
T
d
)
\sum_{d|T}[g(d)<=a]g(d)*\mu(\frac{T}{d})
∑d∣T[g(d)<=a]g(d)∗μ(dT)
我们可以把询问离线下来,按照
a
a
a 从小到大排序
然后用每个
g
(
d
)
g(d)
g(d) 来更新
h
(
T
)
h(T)
h(T),这样全部更新一遍的复杂度大概是
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
每个答案可以用数论分块
O
(
n
)
O(\sqrt n)
O(n) 求出
这里的
h
(
T
)
h(T)
h(T) 因为需要满足单点修改和区间求和的操作,所以可以用常数较小的树状数组来实现
时间复杂度
O
(
n
l
o
g
n
n
)
O(nlogn\sqrt n)
O(nlognn)
#include <bits/stdc++.h>
#define lowbit(x) x&-x
#define int long long
using namespace std;
typedef pair<int,int> pii;
const int N(100100),Q(20100);
struct Query{
int n,m,a,id;
}query[Q];
int g[N],h[N],ANS[Q];
int pr[N],cnt,v[N],mu[N];
pii sortg[N];
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
bool cmp(const Query &x,const Query &y){
return x.a<y.a;
}
void init(){
mu[1]=1;
for(int i=2;i<N;i++){
if(!v[i]) v[i]=pr[++cnt]=i,mu[i]=-1;
for(int j=1;i<=(N-1)/pr[j];j++){
v[pr[j]*i]=pr[j];
if(v[i]==pr[j]) break;
mu[pr[j]*i]=-mu[i];
}
}
for(int i=1;i<N;i++)
for(int j=i;j<N;j+=i)
g[j]+=i;
for(int i=1;i<N;i++)
sortg[i]=make_pair(g[i],i);
sort(sortg+1,sortg+N);
}
void add(int x,int c){
for(;x<N;x+=lowbit(x))
h[x]+=c;
}
int ask(int x){
int res=0;
for(;x;x-=lowbit(x))
res+=h[x];
return res;
}
int get_next(int n,int k){
return n/(n/k);
}
signed main(){
init();
int q=read();
for(int i=1;i<=q;i++)
query[i].n=read(),query[i].m=read(),query[i].a=read(),query[i].id=i;
sort(query+1,query+q+1,cmp);
int p=1;
for(int i=1;i<=q;i++){
while(p<N&&sortg[p].first<=query[i].a){
int d=sortg[p].second;
for(int j=d;j<N;j+=d)
add(j,mu[j/d]*g[d]);
p++;
}
int Newn=min(query[i].n,query[i].m);
int ans=0;
for(int l=1;l<=Newn;){
int r=min(Newn,min(get_next(query[i].n,l),get_next(query[i].m,l)));
ans+=(ask(r)-ask(l-1))*(query[i].n/l)*(query[i].m/l);
l=r+1;
}
ANS[query[i].id]=ans;
}
for(int i=1;i<=q;i++)
printf("%lld\n",ANS[i]%(1ll<<31));
return 0;
}