【一句话题意】求函数
f
h
t
(
n
,
m
)
=
Σ
i
=
1
n
Σ
j
=
1
m
(
n
  
m
o
d
  
i
)
∗
(
m
  
m
o
d
  
j
)
fht(n,m)=\Sigma^n_{i=1}\Sigma^m_{j=1}(n\;mod\;i)*(m\;mod\;j)
fht(n,m)=Σi=1nΣj=1m(nmodi)∗(mmodj)的值。
n
,
m
<
=
1
e
9
n,m<=1e9
n,m<=1e9
【分析】首先拆开求和式子得到
Σ
i
=
1
n
Σ
j
=
1
m
(
n
  
m
o
d
  
i
)
∗
(
m
  
m
o
d
  
j
)
=
=
Σ
i
=
1
n
(
n
  
m
o
d
  
i
)
∗
Σ
j
=
1
m
(
m
  
m
o
d
  
j
)
\Sigma^n_{i=1}\Sigma^m_{j=1}(n\;mod\;i)*(m\;mod\;j)==\Sigma^n_{i=1}(n\;mod\;i)*\Sigma^m_{j=1}(m\;mod\;j)
Σi=1nΣj=1m(nmodi)∗(mmodj)==Σi=1n(nmodi)∗Σj=1m(mmodj)
这样就可以化
O
(
n
m
)
O(nm)
O(nm)算法为
O
(
n
+
m
)
O(n+m)
O(n+m)算法。但是n和m大于1e8,所以优化的程度不够,这个时候就需要优秀的数学变换。证明如下。
Σ
i
=
1
n
(
n
  
m
o
d
  
i
)
\Sigma^n_{i=1}(n\;mod\;i)
Σi=1n(nmodi)
=
Σ
i
=
1
n
(
n
−
⌊
n
i
⌋
∗
i
)
=\Sigma^n_{i=1}(n- \lfloor \frac{n}{i}\rfloor*i)
=Σi=1n(n−⌊in⌋∗i)
=
Σ
i
=
1
n
n
−
Σ
i
=
1
n
i
∗
Σ
i
=
1
n
⌊
n
i
⌋
=\Sigma^n_{i=1}n-\Sigma^n_{i=1 }i*\Sigma^n_{i=1}\lfloor \frac{n}{i}\rfloor
=Σi=1nn−Σi=1ni∗Σi=1n⌊in⌋
=
n
2
−
n
∗
i
∗
Σ
i
=
1
n
⌊
n
i
⌋
=n^2-n*i*\Sigma^n_{i=1}\lfloor \frac{n}{i}\rfloor
=n2−n∗i∗Σi=1n⌊in⌋
一个明显的可以整除分块的式子,对于
⌊
n
i
⌋
\lfloor \frac{n}{i}\rfloor
⌊in⌋其实只有
2
n
2\sqrt n
2n种情况。在i小于
n
\sqrt n
n时
⌊
n
i
⌋
\lfloor \frac{n}{i}\rfloor
⌊in⌋的值其实是不连续的,共有
n
\sqrt n
n种情况。当i大于
n
\sqrt n
n时,
⌊
n
i
⌋
\lfloor \frac{n}{i}\rfloor
⌊in⌋的值一定连续且只有
n
\sqrt n
n种情况。
【code】
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll P=1e9+7;
ll n,m;
inline ll calc(ll x){
ll j,s,ans=x*x;
for (ll i=1;i<=x;i++){
j=x/(x/i);//特别体会一下这句话,可以用参变分离证明一下j是x/i中最大的i。
ans=ans-(i+j)*(j-i+1)/2*(x/i);
i=j;//传递上界为下一组值的下界
}
return ans%P;
}
int main(){
scanf("%lld%lld",&n,&m);
cout<<calc(n)%P*calc(m)%P<<endl;
return 0;
}