快速荷叶叶变换 fht.cpp

版权声明:写得不好,随便转载,但请注明出处,感激不尽 https://blog.csdn.net/xyc1719/article/details/83447241

【一句话题意】求函数 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) 的值。 n , m < = 1 e 9 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)
这样就可以化 O ( n m ) O(nm) 算法为 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 = 1 n ( n n i i ) =\Sigma^n_{i=1}(n- \lfloor \frac{n}{i}\rfloor*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
= n 2 n i Σ i = 1 n n i =n^2-n*i*\Sigma^n_{i=1}\lfloor \frac{n}{i}\rfloor
一个明显的可以整除分块的式子,对于 n i \lfloor \frac{n}{i}\rfloor 其实只有 2 n 2\sqrt n 种情况。在i小于 n \sqrt n n i \lfloor \frac{n}{i}\rfloor 的值其实是不连续的,共有 n \sqrt n 种情况。当i大于 n \sqrt n 时, n i \lfloor \frac{n}{i}\rfloor 的值一定连续且只有 n \sqrt 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;
}

猜你喜欢

转载自blog.csdn.net/xyc1719/article/details/83447241
cpp