题意: 给定$n,k$,问$\sum_{i=1}^{n}k\bmod i$,其中$1\leq n,k\leq 10^9$
题解:
由:$k \bmod i = k - \lfloor \frac{k}{i} \rfloor \times i$
得:$\sum_{i=1}^{n}k\bmod i = n\times k - \sum_{i=1}^k \lfloor \frac{k}{i} \rfloor\times i $
可以知道一定有一些数$i$的$\lfloor \frac{k}{i} \rfloor$相同,这里采用分块思想:
设$acount = \lceil \sqrt{n} \rceil$,对于长度为$n$的块,分为$acount$块,其中第一块的数为$[1,acount]$,第二块为$[acount+1,2\times acount]$,第$acount$块为$[\lfloor \sqrt{n} \rfloor \times acount + 1, n]$。
所以整个式子可以按照$acount$块统一计算,同一块数的$\lfloor \frac{k}{i} \rfloor$相同,长度为$min(n, k / (k / i)) - i + 1$,这里的$i$是一个块的左端点,$min(n, k / (k / i))$是一个块的右端点。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
struct Node{
int x, y;
};
inline ll read() {
ll x = 0, f = 1;
char ch = getchar();
while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar(); }
while(isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
return x * f;
}
void solve() {
ll n = read();
ll k = read();
ll res = n * k;
//i表示元素序列,k/i表示元素所在块号,gx表示该块末尾元素
for(ll i = 1, gx; i <= n; i = gx + 1) {
ll num = k / i;
gx = num ? min(k / num, n) : n;
res -= num * (i + gx) * (gx - i + 1) / 2;
}
printf("%lld\n", res);
}
int main()
{
int T = 1;
//scanf("%d", &T);
for(int i = 1; i <= T; ++i){
solve();
}
return 0;
}