一些实现上的东西与一些小技巧
sqrt 的精度范围支持到 9e15 左右
更大的精度要求需要 sqrtl
测试代码:
#include <bits/stdc++.h>
using namespace std;
const int Max = 1e8, Rg = 10, Block = 1e6;
int main() {
for(int i = 1; i <= Max; ++i) {
if(i % Block == 0) cerr << "Ok: Block " << i / Block << endl;
for(int j = -Rg; j <= Rg; ++j) {
int k = sqrt(1ll * i * i + j);
if(k == i && j < 0) cerr << "Waring: " << i << " " << j << endl;
if(k < i && j >= 0) cerr << "Waring: " << i << " " << j << endl;
}
}
// Waring from 67108865 -1
}
long long 一般可以存下 9 * mod * mod 大小的数,
unsigned long long 一般可以存下 18 * mod * mod 大小的数
当累积的数大多较小,但有部分是 long long 范围时,可以考虑如下代码:
const long long L = 8e18;
void TryMod(long long &s, const int p) { if(s <= -L || s >= L) s %= p; }
数论分块的一种优化
\[\begin{aligned}
\sum_{i=1}^n f(i)\left\lfloor\frac{n}{i}\right\rfloor&=\sum_{i=1}^n f(i)\sum_{ij\le n}1 \\
&=\sum_{ij\le n}f(i)\left(\left[i\le\sqrt{n}\right]+\left[j\le\sqrt{n}\right]-\left[i,j\le\sqrt{n}\right]\right) \\
&=\sum_{i\le\sqrt{n}}\sum_{j\le n/i}f(i)+\sum_{j\le\sqrt{n}}\sum_{i\le n/j}f(i)-\sum_{i,j\le\sqrt{n}}f(i) \\
&=\sum_{i\le\sqrt{n}}f(i)\left\lfloor\frac{n}{i}\right\rfloor+\sum_{i\le\sqrt{n}}\sum_{j\le n/i}f(j)-\left\lfloor\sqrt{n}\right\rfloor\sum_{i\le\sqrt{n}}f(i)
\end{aligned}\]
发现只需少量的除法与枚举,例如筛:
\[\begin{aligned}
\sum_{i=1}^n\sigma(i)&=\sum_{i=1}^n i\left\lfloor\frac{n}{i}\right\rfloor \\
&=-\frac{1}{2}\left\lfloor\sqrt{n}\right\rfloor^2(\left\lfloor\sqrt{n}\right\rfloor+1)+\sum_{i\le\sqrt{n}}i\left\lfloor\frac{n}{i}\right\rfloor+\frac12\left(\left\lfloor\frac{n}{i}\right\rfloor+1\right)\left\lfloor\frac{n}{i}\right\rfloor
\end{aligned}\]
const int q = sqrt(s);
long long ans = -1ll * q * q % p * (q + 1);
for(int i = 1; i <= q; ++i) {
const int x = (s / i) % p;
TryMod(ans += 1ll * (x + 2 * i + 1) * x, p);
}
// ans = 2sum i=1~n sigma(i)
除 \(2\) 的一种简洁写法
const int Inv2 = (1 + Mod) / 2;
int Div2(int x) {
if(x & 1) x += Mod;
return x / 2;
}
可以通过对分子/分母辗转相除以还原分数
#include <bits/stdc++.h>
using namespace std;
const int Mod = 998244353;
pair<int, int> Reduce(int q, int A) {
int x1 = q, y1 = 1, x2 = Mod, y2 = 0;
while(x1 > A) {
swap(x1, x2), swap(y1, y2);
y1 -= y2 * (x1 / x2), x1 %= x2;
}
return pair<int, int>(x1, y1);
}
void Print(pair<int, int> o) {
printf("%d / %d\n", o.first, o.second);
}
int main() {
Print(Reduce(499122177, 10)); // Output: 1 / 2
Print(Reduce(665496237, 10)); // Output: 5 / 3
Print(Reduce(124780545, 10)); // Output: 7 / 8
}
inline 用处很大,register 完全没用
一些标准库函数,如 max 和 min,可以对基本类型手写一遍,促进编译器更好的优化

浙公网安备 33010602011771号