题解:BISHI42 余数求和
题目链接
题目描述
给定正整数 ,计算
。
解题思路
将求和拆成两部分:当 时,有
,贡献为
;其余
用整除分块:
。令
,在区间
上
不变,且
,于是区间贡献为
。
整体复杂度
。
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
long long n, k;
if (!(cin >> n >> k)) return 0;
long long r = min(n, k);
__int128 ans = ( (__int128)(n - r) ) * k;
long long i = 1;
while (i <= r) {
long long q = k / i;
long long R = min(r, k / q);
long long cnt = R - i + 1;
__int128 sum_i = (__int128)(i + R) * cnt / 2;
ans += (__int128)cnt * k - (__int128)q * sum_i;
i = R + 1;
}
unsigned long long out = (unsigned long long)ans;
cout << out << '\n';
return 0;
}
import java.io.*;
public class Main {
static class FastScanner {
private final InputStream in;
private final byte[] buffer = new byte[1 << 16];
private int ptr = 0, len = 0;
FastScanner(InputStream is) { this.in = is; }
private int read() throws IOException {
if (ptr >= len) { len = in.read(buffer); ptr = 0; if (len <= 0) return -1; }
return buffer[ptr++];
}
long nextLong() throws IOException {
int c; long sgn = 1, x = 0;
do { c = read(); } while (c <= 32);
if (c == '-') { sgn = -1; c = read(); }
while (c > 32) { x = x * 10 + (c - '0'); c = read(); }
return x * sgn;
}
}
public static void main(String[] args) throws Exception {
FastScanner fs = new FastScanner(System.in);
long n = fs.nextLong();
long k = fs.nextLong();
long r = Math.min(n, k);
// use BigInteger-like via long with care; values fit in 128-bit in C++, here we manage by splitting
// We'll accumulate in long using careful ordering since bounds通常在1e12内;若更大,可改为 BigInteger
// 仍保持模板清晰:用两个 long 累加不同项避免中间溢出
long i = 1;
// base
java.math.BigInteger ans = java.math.BigInteger.valueOf(n - r).multiply(java.math.BigInteger.valueOf(k));
while (i <= r) {
long q = k / i;
long R = Math.min(r, k / q);
long cnt = R - i + 1;
java.math.BigInteger sum_i = java.math.BigInteger.valueOf(i + R)
.multiply(java.math.BigInteger.valueOf(cnt))
.divide(java.math.BigInteger.valueOf(2));
ans = ans.add(java.math.BigInteger.valueOf(cnt).multiply(java.math.BigInteger.valueOf(k))
.subtract(java.math.BigInteger.valueOf(q).multiply(sum_i)));
i = R + 1;
}
System.out.println(ans.toString());
}
}
import sys
data = sys.stdin.buffer.read().split()
n = int(data[0]); k = int(data[1])
r = min(n, k)
ans = (n - r) * k
i = 1
while i <= r:
q = k // i
R = min(r, k // q)
cnt = R - i + 1
sum_i = (i + R) * cnt // 2
ans += cnt * k - q * sum_i
i = R + 1
print(ans)
算法及复杂度
- 算法:整除分块,分
与
两段;同商区间合并计算
- 时间复杂度:
- 空间复杂度: