1. 程式人生 > 實用技巧 >【整除分塊】 餘數之和

【整除分塊】 餘數之和

傳送門

題意

給定正整數\(n,k\),計算\((k \; mod\; 1)+(k\; mod\; 2)+(k\; mod\; 3)+\dots +(k\; mod\; n)\)的值,

資料範圍

\(1\leq n,k \leq 10^{9}\)

題解

證明\(\sum_{i=1}^{n}\left\lfloor\frac{k}{i}\right\rfloor \times i\)最多隻有\(2 \sqrt{k}\)個值,

  • 當$ i \leq \sqrt{k}\(的時候,最多有\)\sqrt{k}$個不同的取值
  • \(i>\sqrt{k}\)的時候,\(\left\lfloor\frac{k}{i}\right\rfloor < \sqrt{k}\)
    , 故最多有\(\sqrt{k}\)個不同的取值

易知\(\left\lfloor\frac{k}{x}\right\rfloor\)相同的必定是連續的,若某一個相等區間\(x\)是下界,上界是\(\left\lfloor\frac{k}{\left\lfloor\frac{k}{x}\right\rfloor}\right\rfloor\)
時間複雜度:\(O(\sqrt{k})\)
證明:
\(l = x\)\(r = \left\lfloor\frac{k}{\left\lfloor\frac{k}{x}\right\rfloor}\right\rfloor\), \(\left\lfloor\frac{k}{x}\right\rfloor\)

顯然隨著\(x\)增加減少,
\(\because\left\lfloor\frac{k}{x}\right\rfloor\leq \frac{k}{x}\)\(\therefore r \geqslant\left\lfloor\frac{k}{\left(\frac{k}{x}\right)}\right\rfloor=x\),
\(\therefore\left\lfloor\frac{k}{r}\right\rfloor \leq\left\lfloor\frac{k}{x}\right\rfloor\)
\(\begin{array}{l}\because r \leq \frac{k}{\left\lfloor\frac{k}{x} \rfloor\right.} , \therefore \left\lfloor\frac{k}{r}\right\rfloor \geqslant\left\lfloor\frac{k}{\frac{k}{\left\lfloor\frac{k}{x}\right\rfloor}}\right\rfloor\end{array}\)

\(\therefore \left\lfloor\frac{k}{r}\right\rfloor \geqslant x\)
綜上,\(\left\lfloor \frac{k}{r}\right\rfloor=\left\lfloor\frac{k}{x}\right\rfloor\)
\(\because i \in\left[x,\left\lfloor\frac{k}{\left\lfloor\frac{k}{x}\right\rfloor}\right\rfloor\right]\)區間內的數,\(\lfloor\frac{k}{i}\rfloor\)的值都相等

Code


#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll ans;
int main(){
    ll n,k,l,r;
    cin>>n>>k;
    ans=n*k;
    for(l = 1;l<=n;l=r+1){
        if(k/l == 0) break;//0對答案無貢獻
        r=min(k/(k/l),n);
        ans-=(ll) (k/l) *(l+r)  *(r-l+1)/2;//等差數列
    }
    cout<<ans<<endl;
}

時間複雜度\(O(\sqrt{k})\)