首先考虑所有n>k的部分:k mod n=k,答案直接+k*(n-k)。
接下来考虑n属于区间[1,ceil(sqrt(k))]的情况。因为sqrt(k)只有5位数而已,可以按照题目要求朴素算一遍。
最后考虑n属于区间[ceil(sqrt(k)),k]的情况:因为k mod n=k-k div n*n,此时k div n最大为ceil(sqrt(k)),最小为1。如果我们知道某个k div n=a,那么我们就可以求出n的取值范围(因为n在这个范围内都满足k div n=a):[k/n]=a等价于k>=an && k<(a+1)n。换句话来说k/(a+1) < n <= k/a。
得到n的取值区间[L,R]后,这部分k mod n的和就是Σ[i=L->R,(k-ai)]。
我们枚举所有的a,并累加各个部分的余数和,这就是答案。总的复杂度为O(sqrt(k))。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**************************************************************
Problem: 1257
User: abcdabcd987
Language: C++
Result: Accepted
Time:8 ms
Memory:1276 kb
****************************************************************/
#include <iostream>
#include <cmath>
using namespace std ;
long long ans , n , k ;
int main () {
ios :: sync_with_stdio ( false );
cin >> n >> k ;
if ( n > k ) {
ans += k * ( n - k );
n = k ;
}
long long sqrtk = ceil ( sqrt ( k ));
for ( long long i = 1 ; i <= sqrtk ; ++ i ) ans += k % i ;
for ( long long a = 1 ; a <= sqrtk ; ++ a ) {
long long L = floor ( k / ( a + 1 )) + 1 ;
long long R = floor ( k / a );
if ( L <= sqrtk ) L = sqrtk + 1 ;
if ( R > n ) R = n ;
if ( R < L ) continue ;
ans += (( k << 1 ) - a * L - a * R ) * ( R - L + 1 ) >> 1 ;
}
cout << ans ;
}
2013-03-03 UPDATE: 发现一个更厉害的分段方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <cmath>
#include <cstdio>
#include <algorithm>
long long n , k , ans ;
int main ()
{
scanf ( "%lld%lld" , & n , & k );
if ( n > k )
{
ans += ( n - k ) * k ;
n = k ;
}
ans += n * k ;
for ( long long i = 1 , last ; i <= n ; i = last + 1 )
{
last = std :: min ( n , k / ( k / i ));
ans -= ( k / i ) * ( i + last ) * ( last - i + 1 ) / 2 ;
}
printf ( "%lld" , ans );
}