题解:P14813 [CCPC 2024 哈尔滨站] 奇怪的上取整

· · 题解

题面展示

多次询问,每次问 $\sum_{i=1}^{n}f(n,i)$。 ### 解题思路 在洛谷 VP 的本场比赛。这里展示赛时写法。 众所周知,当 $i$ 取不大于 $n$ 的正整数时,$\lfloor\frac{n}{i}\rfloor$ 的取值总数不超过 $O(\sqrt n)$ 个。 合理怀疑换成向上取整也同样适用。 实际上,当我们把向下取整换成向上取整时,当且仅当 $i$ 是 $n$ 的因子时结果不变,否则结果会加上 $1$。 数论分块处理到一个区间 $[l,r]$ 时,由于这个区间都满足 $\lfloor\frac{n}{i}\rfloor$ 相等且 $\frac{n}{i}$ 递减,所以只有 $r$ 可能是 $n$ 的因数。 因此进行数论分块并特判 $r$ 即可。 如何快速计算 $f(a,b)$。 注意到数论分块处理的过程中 $b$ 是递增的,所以 $\frac{a}{b}$ 是递减的。 预处理出 $n$ 的所有因子,然后在数论分块处理的时候双指针即可。 总复杂度 $O(T\sqrt n)$。 写了一份之后,发现跑了 2s,拼尽全力卡常**卡了两个小时**卡到 1.02s 然后就卡不动了。 考虑到数论分块的常数很大,将前 $\sqrt n$ 项剥出来单独处理,这样常数几乎少了一半就通过了。 ### 代码展示 由于这份代码辗转与我和队友的电脑上(轮流卡常),因此码风比较混乱。 当然后来发现不用卡。 ```cpp #include <bits/extc++.h> using namespace std; namespace hd { const int mod = 998244353; struct modint { int val; modint() { val = 0; } modint(int _v) { val = _v; } friend modint operator+(const modint &a, const modint &b) { modint res; res.val = a.val + b.val; res.val = res.val >= mod ? res.val - mod : res.val; return res; } friend modint operator*(const modint &a, const modint &b) { modint res; res.val = 1ll * a.val * b.val % mod; return res; } void operator+=(const modint &a) { val += a.val; val = val >= mod ? val - mod : val; } void operator*=(const modint &a) { val = 1ll * val * a.val % mod; } friend modint operator-(const modint &a, const modint &b) { modint res; res.val = a.val - b.val; res.val = res.val < 0 ? res.val + mod : res.val; return res; } void operator-=(const modint &a) { val -= a.val; val = val < 0 ? val + mod : val; } modint inv() { modint a = val; int b = mod - 2; modint res = 1; while (b) { if (b & 1) { res = res * a; } a = a * a; b >>= 1; } return res; } friend modint pow(modint a, int b) { modint res = 1; while (b) { if (b & 1) { res = res * a; } a = a * a; b >>= 1; } return res; } }; struct FSI { template <typename T> friend FSI &operator>>(FSI &in, T &res) { res = 0; T f = 1; char ch = getchar(); while (!isdigit(ch) && ch != EOF) { if (ch == '-') f = -1; ch = getchar(); } if (ch == EOF) { res = 0; return in; } while (isdigit(ch) && ch != EOF) { res = (res * 10) + (ch - 48); ch = getchar(); } res *= f; return in; } }; template <> FSI &operator>>(FSI &in, string &res) { res.clear(); char ch = getchar(); while ((isblank(ch) || ch == '\n') && ch != EOF) { ch = getchar(); } if (ch == EOF) { res = ""; return in; } while (!isblank(ch) && ch != '\n' && ch != EOF) { res.push_back(ch); ch = getchar(); } return in; } static FSI sr; struct FSO { template <typename T> friend FSO &operator<<(FSO &out, T res) { static std::streambuf *outbuf = cout.rdbuf(); static char stack[110]; static int top = 0; if (res < 0) { outbuf->sputc('-'); res = -res; } if (!res) { outbuf->sputc('0'); return out; } while (res) { stack[++top] = res % 10 + '0'; res /= 10; } while (top) { outbuf->sputc(stack[top]); --top; } return out; } }; template <> FSO &operator<<(FSO &in, string res) { static std::streambuf *outbuf = cout.rdbuf(); outbuf->sputn(res.c_str(), res.size()); return in; } template <> FSO &operator<<(FSO &in, const char *res) { static std::streambuf *outbuf = cout.rdbuf(); outbuf->sputn(res, strlen(res)); return in; } template <> FSO &operator<<(FSO &in, modint res) { static std::streambuf *outbuf = cout.rdbuf(); in << res.val; return in; } static FSO sw; static bool flag = false; void inter(bool f = true) { flag = f; } struct FSE { friend FSO &operator<<(FSO &out, FSE &in) { static std::streambuf *outbuf = cout.rdbuf(); outbuf->sputc('\n'); if (flag) { cout.flush(); } return out; } }; static FSE sendl; FSO &endl(FSO &in) { in << sendl; return in; } FSO &operator<<(FSO &in, FSO &(*f)(FSO &)) { return f(in); } } // namespace hd using i64 = long long; using namespace hd; int n; int f[1000005],cnt,i,l,r,p; long long ans; void solve() { sr >> n; cnt=ans=0; for (i = 1; i * i <= n; ++i) { if (n % i == 0) { f[++cnt] = i; ans+=n/i; } else ans+=n/f[cnt]; } l=i; for (i = cnt - (f[cnt] * f[cnt] == n); i >= 1; i--) { f[++cnt] = n / f[i]; } while (l<=n){ r=n/(n/l); while (f[cnt - 1] >= n/l + 1) --cnt; ans += (long long)(r - l) * f[cnt]; if (f[cnt - 1] >= n/l && r*(n/l)==n) --cnt; ans += f[cnt]; l=r+1; } sw << ans << "\n"; } signed main() { ios::sync_with_stdio(0); // int st = clock(); int t; sr >> t; while (t--) solve(); // int ed = clock(); // cout << "Time: " << 1.0 * (ed - st) / CLOCKS_PER_SEC << "s\n"; return 0; } ```