- 例1
在一些数论题中,经常会碰到类似这样的式子:
这个式子看似需要O(n)的时间复杂度计算,但实际上并不需要,因为有时候对于不同的, 的结果是一样的,所以可以通过整除分块来得到一个的算法。
整除分块:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,ans=0;
cin>>n;
for(int l=1,r;l<=n;l=r+1){
r=n/(n/l);
ans+=(r-l+1)*(n/l);
}
cout<<ans<<"\n";
}
再来看一个例子。
- 例2
这个式子怎么算更快呢?知道的值后,把,用等差数列求和算出来,其余部分分块就好了。
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,ans=0;
cin>>n;
for(int l=1,r;l<=n;l=r+1){
r=n/(n/l);
ans+=(l+r)*(r-l+1)/2 *(n/l);//l,r的等差数列求和 首项加尾项乘以项数除以2
}
cout<<ans<<"\n";
}
如果是这样呢?
还是用相同的方法算,换一个计算公式而已,我们把等差数列求和换成平方数列求和的公式。
#include<bits/stdc++.h>
using namespace std;
int cal(int x){
return x*(x+1)*(2*x+1)/6;
}
int main(){
int n,ans=0;
cin>>n;
for(int l=1,r;l<=n;l=r+1){
r=n/(n/l);
ans+=(cal(r)-cal(l-1))*(n/l);
}
cout<<ans<<"\n";
}
- 例3
可能在做题目的过程中你还会碰到这样的式子
就是求在内的所有倍数和。如果正常算这个式子要的时间。但其实这个求和也可以在的时间内实现。
分析:
对于每个,n里会存在个的倍数,而且等差,公差为。所以式可以写成
可用整除分块,快速求出。
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,ans1=0,ans2=0;
cin>>n;
for(int k=1;k<=n;k++)
for(int j=1;j*k<=n;j++)
ans1+=j*k;
for(int l=1,r;l<=n;l=r+1){
r=n/(n/l);
ans2+=(l+r)*(r-l+1)/2 *(1+n/l)*(n/l)/2;
}
cout<<ans1<<" "<<ans2<<"\n";
}