題目連結
題意:
  給定n,k,求 ∑(k mod i) {1<=i<=n} 其中 n,k<=10^9
  即 k mod 1 + k mod 2 + k mod 3 + … + k mod n的值。


我們先來看商之和。
  給定n,k,求∑(k/i) {1<=i<=n} 其中/為整除。


可以得到一個引理,k/i值的個數不超過2*√k
證明:k整除小於√k的數,都會有一個不同的結果;k整除大於√k的數,結果肯定小於√k,所以最多也只能有√k種結果。

於是我們可以列舉結果的取值累加。是O(√k)級別的。

程式碼可以這樣寫:

LL sum(LL n,LL k){ //calc sigma(k/i) 1<=i<=n
    LL sum = ;
     ; i <= n ; i ++ ){
        LL a = k / i ; LL b = k / a ;
        b = min(b,n) ;
        sum += a * (b-i+) ;
    }
    return sum;
}

其中ak/i的值,b是最大得到k/i這個值的數,b-i+1為取得同一個值的區間長度。

然後來看餘數之和:
我們知道 a mod b == a - a/b*b (整除)。
  於是 ∑(k mod i) {1<=i<=n}就可以寫成n*k-∑k/i*i {1<=i<=n}對於k/i值相同的一段,後面那一項是一個等差數列,求和就好了。

/**************************************************************
    Problem: 1257
    User: zrts
    Language: C++
    Result: Accepted
    Time:8 ms
    Memory:1272 kb
****************************************************************/

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>

//by zrt
//problem:
using namespace std;
typedef long long LL;
const int inf(0x3f3f3f3f);
);
LL n,k;
int main(){
    #ifdef LOCAL
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    scanf("%lld%lld",&n,&k);
    LL ans=n*k;
    LL sub=;
    ;i<=n&&i<=k;i++){
        LL a=k/i;LL b=k/a;
        b=min(b,n);
        sub+=a*(i+b)*(b-i+)/;
        i=b;
    }
    printf("%lld\n",ans-sub);
    ;
}

另有一道題:切巧克力。在SegmentFault上有人提問,連結。我的回答就是用了與這個類似的方法。