淺談整除分塊
前言
我們在學習整除分塊之前,首先你得整除分塊就是是個什麼,它跟分塊(區間操作)相似但是不同(我學的時候有點小懵一直以爲是分塊然後額)。
我是在學習莫比烏斯反演的時候看到要先學前置知識整除分塊,於是去學習。(整除分塊比狄利克雷卷積簡單多了,雖然我到現在還是不會狄利克雷卷積和莫比烏斯反演。)
例題
洛谷
餘數求和
給出正整數n和k,計算G(n, k)=k mod 1 + k mod 2 + k mod 3 + … + k mod n的值,其中k mod i表示k除以i的餘數。例如G(10, 5)=5 mod 1 + 5 mod 2 + 5 mod 3 + 5 mod 4 + 5 mod 5 …… + 5 mod 10=0+1+2+1+0+5+5+5+5+5=29
推導題意可得
首先數據之大讓你沒有辦法去暴力,所以它的難度是提高+省選-,那麼再次推導,可得式子爲
到此爲止,就是整除分塊的模板了,即求,當然向下取整
到此,離開本題去講整除分塊的模板
整除分塊
以下爲模板
#include<bits/stdc++.h>
using namespace std;
long long n,ans;
int main()
{
scanf("%lld",&n);
for(int l=1,r;l<=n;l=r+1)
{
r=n/(n/l);
ans+=(r-l+1)*(n/l);
cout<<l<<' '<<r<<' '<<ans<<endl;
}
printf("%lld",ans);
}
當然給模板是爲了不用手動打樣例
我們通過模板可以得出
這組數據是怎麼的出來了的呢?
推導過程
當時,我們手動求
可知答案是27,與上面相同,那麼這是爲什麼?
整除分塊,是把除以每一個的商相同的分成一塊
由10的樣例可知
重複的商相同的部分,我們可以在O(1)的時間內求出來
枚舉
區間即對於該區間任何一個數來說, \ \
我們從1開始枚舉,
然後
這樣可以把該序列整除分塊了
然後整除分塊的時間即從O(n)縮減到了O(1)
回到例題
我們在把推導一下
可以得到對於每個區間來說,公式爲(自己推一推,很快滴)
即可得到答案
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
int main() {
ll n,k;
scanf("%lld%lld",&n,&k);
ll ans=n*k;
for(ll l=1,r;l<=n;l=r+1) {
if(k/l!=0) r=min(k/(k/l),n);
else r=n;
ans-=(k/l)*(r-l+1)*(l+r)/2;
}
printf("%lld",ans);
return 0;
}