[NEFUOJ]1507 Fibonacci And Gcd
题目地址 Fibonacci And Gcd
题目大意
F
i
b
1
=
1
,
F
i
b
2
=
1
,
F
i
b
n
=
F
i
b
n
−
1
+
F
i
b
n
−
2
Fib_1=1,Fib_2=1,Fib_n=Fib_{n-1}+Fib_{n-2}
Fib1=1,Fib2=1,Fibn=Fibn−1+Fibn−2求
∑
i
=
1
n
∑
j
=
1
m
g
c
d
(
F
i
b
i
,
F
i
b
j
)
\sum_{i=1}^n\sum_{j=1}^mgcd(Fib_i,Fib_j)
i=1∑nj=1∑mgcd(Fibi,Fibj)结果对1e9+7取模
(
n
≤
1000000
)
(n\leq1000000)
(n≤1000000)
题目分析: 首先看到
g
c
d
(
F
i
b
i
,
F
i
b
j
)
gcd(Fib_i,Fib_j)
gcd(Fibi,Fibj),想到将其转化为
F
i
b
(
g
c
d
(
i
,
j
)
)
Fib(gcd(i,j))
Fib(gcd(i,j)),然后式子就变成了
∑
i
=
1
n
∑
j
=
1
m
F
i
b
g
c
d
(
i
,
j
)
\sum_{i=1}^n\sum_{j=1}^mFib_{gcd(i,j)}
i=1∑nj=1∑mFibgcd(i,j)改为枚举
F
i
b
k
Fib_k
Fibk
∑
k
=
1
m
i
n
(
n
,
m
)
F
i
b
k
∑
i
=
1
n
∑
j
=
1
m
[
g
c
d
(
i
,
j
)
=
=
k
]
\sum_{k=1}^{min(n,m)}Fib_k\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)==k]
k=1∑min(n,m)Fibki=1∑nj=1∑m[gcd(i,j)==k]
对后两个
∑
\sum
∑显然是一个反演的形式,设
f
(
x
)
=
∑
i
=
1
n
∑
j
=
1
m
[
g
c
d
(
i
,
j
)
=
=
x
]
f(x)=\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)==x]
f(x)=i=1∑nj=1∑m[gcd(i,j)==x]
g
(
x
)
=
∑
x
∣
d
f
(
d
)
g(x)=\sum_{x|d}f(d)
g(x)=x∣d∑f(d)反演得
f
(
x
)
=
∑
x
∣
d
μ
(
d
x
)
g
(
d
)
f(x)=\sum_{x|d}\mu(\frac{d}{x})g(d)
f(x)=x∣d∑μ(xd)g(d)当
x
=
1
x=1
x=1时,
f
(
1
)
=
∑
1
∣
d
μ
(
d
1
)
g
(
d
)
f(1)=\sum_{1|d}\mu(\frac{d}{1})g(d)
f(1)=1∣d∑μ(1d)g(d)即
f
(
1
)
=
∑
i
=
1
n
μ
(
i
)
g
(
i
)
f(1)=\sum_{i=1}^n\mu(i)g(i)
f(1)=i=1∑nμ(i)g(i)而对于
g
(
x
)
g(x)
g(x) 将
f
(
x
)
f(x)
f(x) 带入可得
g
(
x
)
=
∑
x
∣
d
∑
i
=
1
n
∑
j
=
1
m
[
g
c
d
(
i
,
j
)
=
=
d
]
g(x)=\sum_{x|d}\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)==d]
g(x)=x∣d∑i=1∑nj=1∑m[gcd(i,j)==d] 即
g
(
x
)
=
∑
i
=
1
n
∑
j
=
1
m
[
x
∣
g
c
d
(
i
,
j
)
]
g(x)=\sum_{i=1}^{n}\sum_{j=1}^{m}[x|gcd(i,j)]
g(x)=i=1∑nj=1∑m[x∣gcd(i,j)]进一步变形
g
(
x
)
=
∑
i
=
1
⌊
n
x
⌋
∑
j
=
1
⌊
m
x
⌋
[
1
∣
g
c
d
(
i
,
j
)
]
g(x)=\sum_{i=1}^{\lfloor \frac{n}{x} \rfloor}\sum_{j=1}^{\lfloor \frac{m}{x} \rfloor}[1|gcd(i,j)]
g(x)=i=1∑⌊xn⌋j=1∑⌊xm⌋[1∣gcd(i,j)]
即
g
(
x
)
=
⌊
n
x
⌋
⌊
m
x
⌋
g(x)=\lfloor \frac{n}{x} \rfloor\lfloor \frac{m}{x} \rfloor
g(x)=⌊xn⌋⌊xm⌋
带回到
f
(
x
)
f(x)
f(x) 中
f
(
1
)
=
∑
i
=
1
m
i
n
(
n
,
m
)
⌊
n
i
⌋
⌊
m
i
⌋
μ
(
i
)
f(1)=\sum_{i=1}^{min(n,m)}\lfloor \frac{n}{i} \rfloor\lfloor \frac{m}{i} \rfloor\mu(i)
f(1)=i=1∑min(n,m)⌊in⌋⌊im⌋μ(i)此时,原式变形为
∑
k
=
1
m
i
n
(
n
,
m
)
F
i
b
k
∑
i
=
1
m
i
n
(
n
,
m
)
⌊
n
i
⌋
⌊
m
i
⌋
μ
(
i
)
\sum_{k=1}^{min(n,m)}Fib_k\sum_{i=1}^{min(n,m)}\lfloor \frac{n}{i} \rfloor\lfloor \frac{m}{i} \rfloor\mu(i)
k=1∑min(n,m)Fibki=1∑min(n,m)⌊in⌋⌊im⌋μ(i)因此只需要线性筛出
μ
\mu
μ函数的前缀和即可在线性的时间复杂度内求出答案。
代码如下
#include<stdio.h>
#include<algorithm>
#include<string.h>
#define mxn 1100000
#define LL long long
#define mod 1000000007
LL mu[mxn],used[mxn],prime[mxn],sum[mxn],Fi[mxn],cnt;
using namespace std;
void swap(LL &a,LL &b){
a+=b;b=a-b;a-=b;
}
void GetMu(){
mu[1]=1;
for(int i=2;i<=mxn;i++){
if(!used[i]){
prime[++cnt]=i;
mu[i]=-1;
}
for(int j=1;j<=cnt&&i*prime[j]<=mxn;j++){
used[i*prime[j]]=1;
if(i%prime[j]==0)break;
else mu[i*prime[j]]=-mu[i];
}
}
for(int i=1;i<=mxn;i++)
sum[i]=sum[i-1]+mu[i];
}
LL Work(LL n,LL m){
LL _sum=0;
if(n>m)swap(n,m);
for(int l=1,r;l<=n;l=r+1){
r=min(n/(n/l),m/(m/l));
_sum=(_sum+(n/l)*(m/l)*(sum[r]-sum[l-1]))%mod;
_sum=(_sum+mod)%mod;
}
return _sum;
}
int main()
{
int t;
scanf("%d",&t);
GetMu();
while(t--){
LL n,m;
scanf("%lld %lld",&n,&m);
if(n>m)swap(n,m);
LL ans=0;
Fi[1]=1;Fi[2]=1;
for(int i=3;i<=n;i++)
Fi[i]=(Fi[i-1]+Fi[i-2])%mod;
for(int i=1;i<=n;i++)
ans=(ans+Fi[i]*Work(n/i,m/i)+mod)%mod;
printf("%lld\n",ans);
}
return 0;
}