Description
神犇YY虐完数论后给傻×kAc出了一题给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对kAc这种
傻×必然不会了,于是向你来请教……多组输入
T = 10000
N, M <= 10000000
Solution
感觉做了这么点反演题终于有点头绪了。。
首先想到枚举gcd
ans=∑d为质数 ∑i=1⌊nd⌋∑j=1⌊md⌋[1=gcd(i,j)]
a
n
s
=
∑
d
为
质
数
∑
i
=
1
⌊
n
d
⌋
∑
j
=
1
⌊
m
d
⌋
[
1
=
g
c
d
(
i
,
j
)
]
然后套路一波设
f(x)=∑i=1n∑j=1m[x=gcd(i,j)]
f
(
x
)
=
∑
i
=
1
n
∑
j
=
1
m
[
x
=
g
c
d
(
i
,
j
)
]
再设
g(x)=∑i=1n∑j=1m[x|gcd(i,j)]
g
(
x
)
=
∑
i
=
1
n
∑
j
=
1
m
[
x
|
g
c
d
(
i
,
j
)
]
显然有
g(x)=∑x|df(d)=⌊nx⌋⌊mx⌋
g
(
x
)
=
∑
x
|
d
f
(
d
)
=
⌊
n
x
⌋
⌊
m
x
⌋
这里是常见形式的其中一种,反演一波得
f(x)=∑x|dμ(dx)g(d)
f
(
x
)
=
∑
x
|
d
μ
(
d
x
)
g
(
d
)
注意到我们一开始要求1的情况,那么观察一波发现
f(1)=∑d=1nμ(d)∗⌊nd⌋⌊md⌋
f
(
1
)
=
∑
d
=
1
n
μ
(
d
)
∗
⌊
n
d
⌋
⌊
m
d
⌋
套进求ans的式子里
ans=∑d为质数 ∑x=1nμ(x)∗⌊ndx⌋⌊mdx⌋
a
n
s
=
∑
d
为
质
数
∑
x
=
1
n
μ
(
x
)
∗
⌊
n
d
x
⌋
⌊
m
d
x
⌋
然鹅发现这样还是不能过时限,考虑令 T=dx T = d x ,枚举T的话又有
∑T=1n⌊nT⌋⌊mT⌋∑d为质数且d|Tμ(Td)
∑
T
=
1
n
⌊
n
T
⌋
⌊
m
T
⌋
∑
d
为
质
数
且
d
|
T
μ
(
T
d
)
那么预处理一波满足条件的
μ
μ
然后分块即可
由于
μ
μ
的取值极小可以考虑用bool或者short之类的卡空间
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
typedef long long LL;
const int N=10000000;
const int M=664581;
int prime[M];
int sum[N+1];
short mu[N+1];
bool not_prime[N+1];
void pre_work() {
mu[1]=1;
rep(i,2,N) {
if (!not_prime[i]) {
prime[++prime[0]]=i;
mu[i]=-1;
}
for (int j=1;j<=prime[0]&&i*prime[j]<=N;j++) {
not_prime[i*prime[j]]=1;
if (i%prime[j]==0) {
mu[i*prime[j]]=0;
break;
}
mu[i*prime[j]]=-mu[i];
}
}
rep(i,1,prime[0]) {
for (int j=prime[i];j<=N;j+=prime[i]) {
sum[j]+=mu[j/prime[i]];
}
}
rep(i,1,N) sum[i]+=sum[i-1];
}
void solve(int n,int m) {
if (n>m) std:: swap(n,m);
LL ans=0;
for (int i=1,j;i<=n;i=j+1) {
j=std:: min(n/(n/i),m/(m/i));
ans+=1ll*(n/i)*(m/i)*(sum[j]-sum[i-1]);
}
printf("%lld\n", ans);
}
int main(void) {
pre_work();
int T; scanf("%d",&T);
while (T--) {
int n,m; scanf("%d%d",&n,&m);
solve(n,m);
}
return 0;
}