标签:min turn block 通过 span fine ifd clu lock
定义函数\(G(n, k) = \sum\limits_{i = 1}^{n} k~mod~i\),给定\(n, k\),求函数\(G\)的值
\(n, k \leq 10^9\)
我一开始看这题的时候居然还懵了一下
因为当\(i > k\)时,余数一定都是\(k\),所以我们只需要考虑\(i \leq k\)的部分怎么求
我们可以把\(k\)表示成\(a \cdot i + b\)的形式,我们发现\(k\)分别整除\([1, k]\)之间的数,最多只会有根号级别的商的个数
我在这里简单证明一下
当除数\(\leq \sqrt k\)时,因为除数只有\(\sqrt k\)个,显然商也只会有\(\sqrt k\)个
当除数\(\gt \sqrt k\)时,因为商会小于\(\sqrt k\),所以商最多也只有\(\sqrt k\)个
所以我们可以通过整除分块来解决这个问题
我们用整除分块找出所有\(a\)相同的\(i\)的区间,在这段区间内\(b\)一定会是一个公差为\(a\)的等差数列,可以直接\(\mathcal{O}(1)\)计算得
所以总的复杂度为\(\mathcal{O}(\sqrt k)\)
#include <bits/stdc++.h>
using namespace std;
#define fst first
#define snd second
#define mp make_pair
#define squ(x) ((LL)(x) * (x))
#define debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef pair<int, int> pii;
template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }
template<typename T> inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }
inline int read() {
int sum = 0, fg = 1; char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == ‘-‘) fg = -1;
for (; isdigit(c); c = getchar()) sum = (sum << 3) + (sum << 1) + (c ^ 0x30);
return fg * sum;
}
int main() {
#ifdef xunzhen
freopen("math.in", "r", stdin);
freopen("math.out", "w", stdout);
#endif
int n = read(), m = read();
LL ans = n > m ? (LL)m * (n - m) : 0;
chkmin(n, m);
for (int l = 1, r = 0; l <= n; l = r + 1) {
r = min(m / (m / l), n);
int r1 = m % r, r2 = m % l;
ans += (LL)(r1 + r2) * ((r2 - r1) / (m / l) + 1) / 2;
}
printf("%lld\n", ans);
return 0;
}
标签:min turn block 通过 span fine ifd clu lock
原文地址:https://www.cnblogs.com/xunzhen/p/10340834.html