BZOJ2694 Lcm
Description
定义整数
A,B
A
,
B
,求所有满足如下条件的
LCM(a,b)
L
C
M
(
a
,
b
)
的和:
1≤a≤A
1
≤
a
≤
A
1≤b≤B
1
≤
b
≤
B
∀n>1,n2∤gcd(a,b)
∀
n
>
1
,
n
2
∤
g
c
d
(
a
,
b
)
答案输出模
230
2
30
对于任意的
>1
>
1
的
n,gcd(a,b)
n
,
g
c
d
(
a
,
b
)
不是
n2
n
2
的倍数
也就是说
gcd(a,b)
g
c
d
(
a
,
b
)
没有一个因子的次数
>=2
>=
2
Input
一个正整数T表示数据组数
接下来T行 每行两个正整数 表示N、M
Output
T行 每行一个整数 表示第i组数据的结果
Sample Input
4
2 4
3 3
6 5
8 3
Sample Output
24
28
233
178
HINT
T <= 10000
N, M<=4000000
首先根据题目要求
ans=∑ni=1∑mj=1lcm(i,j)[μ(gcd(i,j))!=0] a n s = ∑ i = 1 n ∑ j = 1 m l c m ( i , j ) [ μ ( g c d ( i , j ) ) ! = 0 ]
这一步很关键
↑
↑
然后我们可以参照这篇文章把lcm进行展开,在对
gcd(i,j)=d
g
c
d
(
i
,
j
)
=
d
枚举的过程中保留
[μ(d)!=0]
[
μ
(
d
)
!
=
0
]
的限制条件
然后经过一顿展开我们可以得到:
ans=∑upk=1C(⌊nk⌋)C(⌊mk⌋)k∗∑d|kd∗μ(d) [μ(kd)!=0] a n s = ∑ k = 1 u p C ( ⌊ n k ⌋ ) C ( ⌊ m k ⌋ ) k ∗ ∑ d | k d ∗ μ ( d ) [ μ ( k d ) ! = 0 ]
然后我们筛出 k∗∑d|kd∗μ(d) [μ(kd)!=0] k ∗ ∑ d | k d ∗ μ ( d ) [ μ ( k d ) ! = 0 ] 并对其进行前缀和累加
最后下底函数分个块就行了
#include<bits/stdc++.h>
using namespace std;
#define N 4000010
#define LL long long
int T,n,m,tot=0,Mod=1;
int pri[N],mu[N];
LL F[N],C[N];
bool mark[N]={0};
void init(){
for(int i=1;i<=30;i++)Mod*=2;
mu[1]=1;
for(int i=2;i<N;i++){
if(!mark[i])pri[++tot]=i,mu[i]=-1;
for(int j=1;j<=tot&&i*pri[j]<N;j++){
mark[i*pri[j]]=1;
if(i%pri[j]==0)mu[i*pri[j]]=0;
else mu[i*pri[j]]=-mu[i];
}
}
for(int i=1;i<N;i++)
for(int j=1;i*j<N;j++)
if(mu[j])F[i*j]+=mu[i]*i;
for(int i=1;i<N;i++)F[i]=(1ll*F[i]*i+F[i-1]+Mod)%Mod;
for(int i=1;i<N;i++)C[i]=(1ll*(i+1)*i/2)%Mod;
}
int main(){
init();
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
LL ans=0;
int up=min(n,m);
for(int i=1,j;i<=up;i=j+1){
j=min(n/(n/i),m/(m/i));
ans=(ans+(F[j]-F[i-1])*C[n/i]*C[m/i]%Mod+Mod)%Mod;
}
printf("%lld\n",ans);
}
return 0;
}