【一句话题意】求函数fht(n,m)=Σi=1nΣj=1m(n  mod  i)∗(m  mod  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<=1e9n,m<=1e9n,m<=1e9
【分析】首先拆开求和式子得到Σi=1nΣj=1m(n  mod  i)∗(m  mod  j)==Σi=1n(n  mod  i)∗Σj=1m(m  mod  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(nm)O(nm)O(nm)算法为O(n+m)O(n+m)O(n+m)算法。但是n和m大于1e8,所以优化的程度不够,这个时候就需要优秀的数学变换。证明如下。
Σi=1n(n  mod  i)\Sigma^n_{i=1}(n\;mod\;i)Σi=1n(nmodi)
=Σi=1n(n−⌊ni⌋∗i)=\Sigma^n_{i=1}(n- \lfloor \frac{n}{i}\rfloor*i)=Σi=1n(n−⌊in⌋∗i)
=Σi=1nn−Σi=1ni∗Σi=1n⌊ni⌋=\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⌋
=n2−n∗i∗Σi=1n⌊ni⌋=n^2-n*i*\Sigma^n_{i=1}\lfloor \frac{n}{i}\rfloor=n2−n∗i∗Σi=1n⌊in⌋
一个明显的可以整除分块的式子,对于⌊ni⌋\lfloor \frac{n}{i}\rfloor⌊in⌋其实只有2n2\sqrt n2n种情况。在i小于n\sqrt nn时⌊ni⌋\lfloor \frac{n}{i}\rfloor⌊in⌋的值其实是不连续的,共有n\sqrt nn种情况。当i大于n\sqrt nn时,⌊ni⌋\lfloor \frac{n}{i}\rfloor⌊in⌋的值一定连续且只有n\sqrt nn种情况。
【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;
}