structBarrett { i64 d; i128 b; explicitBarrett(i64 d) : d(d), b(((i128) 1 << 64) / d) { } friend i64 operator %(i64 a, const Barrett &m) { i64 w = (m.b * a) >> 64; w = a - w * m.d; return w >= m.d ? w - m.d : w; } friend i64 operator /(i64 a, const Barrett &d) { i64 w = (d.b * a) >> 64; return a - w * d.d >= d.d ? w + 1 : w; } };
基姆拉尔森计算公式
以 1970 年 1 月 1 日为星期四为基准,累加日期计算 y 年 m 月 d 日是星期几。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
constint ds[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; boolis_leap(int y){ return y % 400 == 0 || (y % 4 == 0 && y % 100 != 0); } intget_days(int y, int m){ return ds[m - 1] + (is_leap(y) && m == 2); } intget_week(int y, int m, int d){ int res = 2; for (int i = 1970; i < y; i++) res += 365 + is_leap(i); for (int i = 1; i < m; i++) res += get_days(y, i); res += d; return res % 7 + 1; }
蔡勒公式
基准相同,可以快速计算任意年份,返回 0 代表星期日。
1 2 3 4 5
intget_week(int y, int m, int d) { if (m == 1 || m == 2) m += 12, y--; return (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400 + 1) % 7; }
i64 l = 0, r = 1e18, al, ar; while (l < r) { i64 ml = (l + r) / 2, mr = ml + 1; al = f(ml), ar = f(mr); while (al == ar && ml > l) al = f(--ml);
if (al >= ar) l = mr; else r = ml; } cout << min(al, ar) << endl;
排序算法
排序算法是将数据排列的方法,在基础排序算法的基础上上可以扩展出更多功能。
快速排序
基于随机选取基数的三路快速排序,是不稳定排序,可以在此基础上修改出线性找第 $k$ 大的数算法。
1 2 3 4 5 6 7 8 9 10 11 12
auto qsort = [&](auto &&self, int l, int r) { if (r - l <= 1) return; auto pivot = a[l + rnd() % (r - l)]; int i = l, j = l, k = r; while (i < k) { if (a[i] < pivot) swap(a[i++], a[j++]); elseif (a[i] > pivot) swap(a[i], a[--k]); else i++; } self(self, l, j); self(self, k, r); };
归并排序
基于分治思想将数组分段排序后合并,是稳定排序,可以在此基础上修改用于解决偏序问题其中一维。
1 2 3 4 5 6 7 8 9 10 11 12 13
auto msort = [&](auto self, int l, int r) { if (r - l <= 1) return; int m = l + r >> 1; self(self, l, m), self(self, m, r); int i = l, j = m, k = l; while (i < m && j < r) { if (a[i] <= a[j]) b[k++] = a[i++]; else b[k++] = a[j++]; } while (i < m) b[k++] = a[i++]; while (j < r) b[k++] = a[j++]; for (i = l; i < r; ++i) a[i] = b[i]; };
搜索算法
搜索,也就是对状态空间进行枚举,通过穷尽所有的可能来找到最优解,或者统计合法解的个数。
Dancing links X 算法
精确覆盖问题要求在给定集合中选取若干互不相交的子集,使得目标集合的每个元素恰好被覆盖一次。
Dancing Links X 算法通过高效回溯和双向链表优化搜索,常用于解决数独、 N 皇后、 Pentomino 拼图等组合优化问题。
structDLX { structnode { int l = 0, r = 0, u = 0, d = 0, row = -1, col = -1; };
vector<node> adj; vector<int> head, sz, ans;
explicitDLX(int r, int c) : adj(c + 1), head(r + 1, -1), sz(c + 1) { for (int i = 0; i <= c; ++i) { adj[i].l = i - 1, adj[i].r = i + 1; adj[i].u = adj[i].d = adj[i].col = i; } adj[0].l = c, adj[c].r = 0; }
voidinsert(int r, int c){ int id = (int) adj.size(); adj.emplace_back(0, 0, adj[c].u, c, r, c); adj[c].u = adj[adj[c].u].d = id; if (head[r] == -1) { head[r] = adj[id].l = adj[id].r = id; } else { int first = head[r]; int last = adj[first].l; adj[id].l = last, adj[id].r = first; adj[last].r = adj[first].l = id; } sz[c]++; }
voidremove(int c){ adj[adj[c].r].l = adj[c].l; adj[adj[c].l].r = adj[c].r; for (int i = adj[c].d; i != c; i = adj[i].d) { for (int j = adj[i].r; j != i; j = adj[j].r) { adj[adj[j].d].u = adj[j].u; adj[adj[j].u].d = adj[j].d; sz[adj[j].col]--; } } }
voidrestore(int c){ for (int i = adj[c].u; i != c; i = adj[i].u) { for (int j = adj[i].l; j != i; j = adj[j].l) { adj[adj[j].d].u = adj[adj[j].u].d = j; sz[adj[j].col]++; } } adj[adj[c].r].l = adj[adj[c].l].r = c; }
booldance(){ if (adj[0].r == 0) returntrue; int c = adj[0].r; for (int i = adj[c].r; i != 0; i = adj[i].r) { if (sz[i] < sz[c]) c = i; } remove(c); for (int i = adj[c].d; i != c; i = adj[i].d) { ans.push_back(adj[i].row); for (int j = adj[i].r; j != i; j = adj[j].r) remove(adj[j].col); if (dance()) returntrue; for (int j = adj[i].l; j != i; j = adj[j].l) restore(adj[j].col); ans.pop_back(); } restore(c); returnfalse; } };
array<array<int, 9>, 9> ma{}; auto get = [&](int x, int y, int k)-> array<int, 4> { int box = x / 3 * 3 + y / 3; return { x * 9 + y + 1, 81 + x * 9 + k + 1, 162 + y * 9 + k + 1, 243 + box * 9 + k + 1 }; };
int id = 0; DLX solver(730, 324); vector<tuple<int, int, int> > rows; for (int x = 0; x < 9; ++x) { for (int y = 0; y < 9; ++y) { if (ma[x][y] != 0) { int k = ma[x][y] - 1; for (int c: get(x, y, k)) solver.insert(id, c); rows.emplace_back(x, y, k); id++; } else { for (int k = 0; k < 9; ++k) { for (int c: get(x, y, k)) solver.insert(id, c); rows.emplace_back(x, y, k); id++; } } } }
solver.dance(); for (int rid: solver.ans) { auto [x, y, k] = rows[rid]; ma[x][y] = k + 1; }
auto get = [&](int x, int k) { vector<int> a{0}; while (x) a.push_back(x % 10), x /= 10; vector mem(a.size(), vector<int>(a.size(), -1)); auto dfs = [&](auto &&self, int pos, bool limit, bool lead0, int sum) -> int { if (!pos) return sum; if (!limit && !lead0 && ~mem[pos][sum]) return mem[pos][sum]; int res = 0; int up = limit ? a[pos] : 9; for (int i = 0; i <= up; i++) { int c0 = lead0 && i == 0; res += self(self, pos - 1, limit && i == up, c0, c0 ? 0 : sum + (i == k)); } if (!limit && !lead0) mem[pos][sum] = res; return res; }; returndfs(dfs, a.size() - 1, true, true, 0); };
int s = 0, c = 0; for (int f = 0; f < n; c += a[f++].c) { if (a[s].x == a[f].x && a[s].y == a[f].y && a[s].z == a[f].z) continue; a[s].c = c, a[s].a = c - 1; a[++s] = a[f], c = 0; } a[s].c = c, a[s].a = c - 1; a.resize(++s);
Fenwick<int> bit(k + 1); auto cdq = [&](auto &&self, int l, int r) -> void { if (r - l <= 1) return; int m = l + r >> 1; self(self, l, m), self(self, m, r); int i = l, j = m; while (j < r) { while (i < m && a[i].y <= a[j].y) bit.add(a[i].z, a[i].c), i++; a[j].a += bit.sum(a[j].z), j++; } for (j = l; j < i; j++) bit.add(a[j].z, -a[j].c); inplace_merge(a.begin() + l, a.begin() + m, a.begin() + r, cmpy); }; cdq(cdq, 0, s);
constint len = (int) pow(n, 0.67); ranges::sort(qs, [&](auto &x, auto &y) { if (x.l / len != y.l / len) return x.l < y.l; if (x.r / len != y.r / len) return x.l / len & 1 ? x.r > y.r : x.r < y.r; return x.r / len & 1 ? x.t < y.t : x.t > y.t; });
auto movet = [&](int i, int val) { auto [x, u, v] = ms[i]; if (val == -1) swap(u, v); a[x] = v; if (x < l || x >= r) return; cnt[u]--, b[bk[u]]--; cnt[v]++, b[bk[v]]++; };
for (auto &q: qs) { while (l > q.l) movelr(--l, 1); while (r < q.r) movelr(r++, 1); while (l < q.l) movelr(l++, -1); while (r > q.r) movelr(--r, -1); while (t < q.t) movet(++t, 1); while (t > q.t) movet(t--, -1); q.ans = query(); }