- 例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";
}