一些实现上的东西与一些小技巧

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 完全没用


一些标准库函数,如 maxmin,可以对基本类型手写一遍,促进编译器更好的优化

posted @ 2023-03-15 12:42  JerryTcl  阅读(69)  评论(0)    收藏  举报