diff --git a/.gitignore b/.gitignore index 8fa0fc1..ca2c0b9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.pdf *.sh *.py +**/.idea \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..3519b16 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.28) + +project(CP-Templates) + +file(GLOB_RECURSE ALL_CPP_FILES "*.cpp") + +add_library(qc_lib ${ALL_CPP_FILES}) diff --git "a/\345\212\250\346\200\201\350\247\204\345\210\222/Dynamic-Convex-Hull.cpp" b/DP/Dynamic-Convex-Hull.cpp similarity index 100% rename from "\345\212\250\346\200\201\350\247\204\345\210\222/Dynamic-Convex-Hull.cpp" rename to DP/Dynamic-Convex-Hull.cpp diff --git "a/\346\225\260\346\215\256\347\273\223\346\236\204/DSU.cpp" b/DataStructure/DSU.cpp similarity index 95% rename from "\346\225\260\346\215\256\347\273\223\346\236\204/DSU.cpp" rename to DataStructure/DSU.cpp index 56a6abb..f7a2d57 100644 --- "a/\346\225\260\346\215\256\347\273\223\346\236\204/DSU.cpp" +++ b/DataStructure/DSU.cpp @@ -1,9 +1,11 @@ +#include + struct DSU { std::vector data; - + void init(int n) { data.assign(n, -1); } - bool merge(int y, int x) { + bool merge(int x, int y) { x = root(x); y = root(y); if (x != y) { @@ -13,9 +15,9 @@ struct DSU { } return x != y; } - + bool same(int x, int y) { return root(x) == root(y); } - + int root(int x) { return data[x] < 0 ? x : data[x] = root(data[x]); } int size(int x) { return -data[root(x)]; } @@ -26,25 +28,25 @@ namespace DSU2 { const static int MAXN = 100000 + 10; int fa[MAXN], ds[MAXN], rk[MAXN]; int S[MAXN], top; - + void init(int n) { for (int i = 1; i <= n; ++i) { fa[i] = i, rk[i] = ds[i] = 0; } top = 0; } - + int dis(int x) { int r(0); for (; x != fa[x]; x = fa[x]) r ^= ds[x]; return r; } - + int get(int x) { while (x != fa[x]) x = fa[x]; return fa[x]; } - + void merge(int x, int y, int d) { x = get(x); y = get(y); @@ -55,7 +57,7 @@ namespace DSU2 { ds[x] = d; S[++top] = x; } - + void restore(int ed) { for (; top > ed; --top) { if (S[top] < 0) --rk[-S[top]]; diff --git "a/\346\225\260\346\215\256\347\273\223\346\236\204/Fenwick-Tree.cpp" b/DataStructure/Fenwick-Tree.cpp similarity index 100% rename from "\346\225\260\346\215\256\347\273\223\346\236\204/Fenwick-Tree.cpp" rename to DataStructure/Fenwick-Tree.cpp diff --git "a/\346\225\260\346\215\256\347\273\223\346\236\204/PBDS.cpp" b/DataStructure/PBDS.cpp similarity index 100% rename from "\346\225\260\346\215\256\347\273\223\346\236\204/PBDS.cpp" rename to DataStructure/PBDS.cpp diff --git "a/\346\225\260\346\215\256\347\273\223\346\236\204/Persistent-Segtree.cpp" b/DataStructure/Persistent-Segtree.cpp similarity index 100% rename from "\346\225\260\346\215\256\347\273\223\346\236\204/Persistent-Segtree.cpp" rename to DataStructure/Persistent-Segtree.cpp diff --git "a/\346\225\260\346\215\256\347\273\223\346\236\204/Segment-Tree.cpp" b/DataStructure/Segment-Tree.cpp similarity index 98% rename from "\346\225\260\346\215\256\347\273\223\346\236\204/Segment-Tree.cpp" rename to DataStructure/Segment-Tree.cpp index d537e65..1c3668c 100644 --- "a/\346\225\260\346\215\256\347\273\223\346\236\204/Segment-Tree.cpp" +++ b/DataStructure/Segment-Tree.cpp @@ -1,4 +1,7 @@ struct SegTree { +#define lson (ind<<1) +#define rson (ind<<1|1) + static const int maxn =; struct node { diff --git "a/\346\225\260\346\215\256\347\273\223\346\236\204/Sparse-Table.cpp" b/DataStructure/Sparse-Table.cpp similarity index 100% rename from "\346\225\260\346\215\256\347\273\223\346\236\204/Sparse-Table.cpp" rename to DataStructure/Sparse-Table.cpp diff --git "a/\345\207\240\344\275\225/Geometry.cpp" b/Geometry/Geometry.cpp similarity index 70% rename from "\345\207\240\344\275\225/Geometry.cpp" rename to Geometry/Geometry.cpp index 2d63ae1..3c885d2 100644 --- "a/\345\207\240\344\275\225/Geometry.cpp" +++ b/Geometry/Geometry.cpp @@ -1,7 +1,11 @@ +#include +#include +#include + using flt = double; using int64 = long long; -const flt eps = 1e-8, pi = acos(-1.0); +const flt eps = 1e-8, pi = std::acos(-1.0); template inline int sgn(T x, T e = eps) { return x < -e ? -1 : x > e; } @@ -17,45 +21,51 @@ inline flt fix(flt x, flt e = eps) { return cmp(x, flt(0), e); } template struct Point { T x, y; - - Point(T x = 0, T y = 0) : x(x), y(y) {} - + + explicit Point(T x = 0, T y = 0) : x(x), y(y) {} + bool operator<(const Point &o) const { return x < o.x || (x == o.x && y < o.y); } - + bool operator==(const Point &o) const { return x == o.x && y == o.y; } - + Point operator+(const Point &o) const { return Point(x + o.x, y + o.y); } - + Point operator-(const Point &o) const { return Point(x - o.x, y - o.y); } - + Point operator*(T k) const { return Point(x * k, y * k); } - + Point operator/(T k) const { return Point(x / k, y / k); } - - T dot(const Point &o) const { return x * o.x + y * o.y; } - - T det(const Point &o) const { return x * o.y - y * o.x; } - - T norm2() const { return x * x + y * y; } - - flt norm() const { return hypot(x, y); } - - flt ang() const { return atan2(y, x); } - - Point perp() const { return Point(-y, x); } // rotate 90 degrees - Point unit() const { return *this / norm(); } - - Point trunc(flt k) const { return unit() * k; } - - // counter clockwise rotate a rad - Point rot(flt a) const { + + [[nodiscard]] T dot(const Point &o) const { return x * o.x + y * o.y; } + + [[nodiscard]] T det(const Point &o) const { return x * o.y - y * o.x; } + + [[nodiscard]] T norm2() const { return x * x + y * y; } + + [[nodiscard]] flt norm() const { return hypot(x, y); } + + [[nodiscard]] flt ang() const { return atan2(y, x); } + + [[nodiscard]] Point perp() const { return Point(-y, x); } // rotate 90 degrees + [[nodiscard]] Point unit() const { return *this / norm(); } + + [[nodiscard]] Point trunc(flt k) const { return unit() * k; } + + // counter-clockwise rotate a rad + [[nodiscard]] Point rot(flt a) const { return Point(x * cos(a) - y * sin(a), x * sin(a) + y * cos(a)); } - - // counter clockwise rotate using cos/sin - Point rot(flt cosa, flt sina) const { + + // counter-clockwise rotate using cos/sin + [[nodiscard]] Point rot(flt cosa, flt sina) const { return Point(x * cosa - y * sina, x * sina + y * cosa); } + + friend std::ostream &operator<<(std::ostream &out, const Point &p) { + out << "(" << p.x << "," << p.y << ")"; + return out; + } + }; using point = Point; @@ -74,12 +84,12 @@ bool is_parallel(const P &a, const P &b, const P &c, const P &d) { // find intersection of segments ab and cd, stored in p template bool seg_inter(const P &a, const P &b, const P &c, const P &d, P &p) { - if(on_seg(a, b, c)) return p = c, true; - if(on_seg(a, b, d)) return p = d, true; - if(on_seg(c, d, a)) return p = a, true; - if(on_seg(c, d, b)) return p = b, true; + if (on_seg(a, b, c)) return p = c, true; + if (on_seg(a, b, d)) return p = d, true; + if (on_seg(c, d, a)) return p = a, true; + if (on_seg(c, d, b)) return p = b, true; P ab{b - a}, cd{d - c}; - if(sgn(ab.det(cd)) == 0) return false; // parallel + if (sgn(ab.det(cd)) == 0) return false; // parallel int d1 = sgn(ab.det(c - a)) * sgn(ab.det(d - a)); int d2 = sgn(cd.det(a - c)) * sgn(cd.det(b - c)); p = a + ab * (cd.det(c - a) / cd.det(ab)); @@ -90,7 +100,7 @@ bool seg_inter(const P &a, const P &b, const P &c, const P &d, P &p) { template bool line_inter(const P &a, const P &b, const P &c, const P &d, P &p) { P ab{b - a}, cd{d - c}; - if(sgn(ab.det(cd)) == 0) return false; // parallel + if (sgn(ab.det(cd)) == 0) return false; // parallel p = a + ab * (cd.det(c - a) / cd.det(ab)); return true; } @@ -99,8 +109,8 @@ bool line_inter(const P &a, const P &b, const P &c, const P &d, P &p) { template flt dis2seg(const P &a, const P &b, const P &o) { P ao{o - a}, bo{o - b}, ab{b - a}; - if(sgn(ao.dot(ab)) < 0) return ao.norm(); - if(sgn(-bo.dot(ab)) < 0) return bo.norm(); + if (sgn(ao.dot(ab)) < 0) return ao.norm(); + if (sgn(-bo.dot(ab)) < 0) return bo.norm(); return std::abs(ao.det(ab)) / ab.norm(); } @@ -108,7 +118,7 @@ flt dis2seg(const P &a, const P &b, const P &o) { template flt dis_seg2seg(const P &a, const P &b, const P &c, const P &d) { P o; - if(seg_inter(a, b, c, d, o)) return 0; + if (seg_inter(a, b, c, d, o)) return 0; else return std::min(std::min(dis2seg(a, b, c), dis2seg(a, b, d)), std::min(dis2seg(c, d, a), dis2seg(c, d, b))); @@ -137,7 +147,7 @@ point reflect(const point &a, const point &b, const point &o) { bool intersect(const point &A, flt ra, const point &B, flt rb, point &P, point &Q) { point AB(B - A); double dis = AB.norm(); - if (sgn(dis) == 0 || sgn (dis - (ra + rb)) > 0 || sgn (dis - fabs (ra - rb)) < 0) return false; + if (sgn(dis) == 0 || sgn(dis - (ra + rb)) > 0 || sgn(dis - fabs(ra - rb)) < 0) return false; flt cosa = (dis * dis + ra * ra - rb * rb) / (2 * dis * ra); flt sina = sqrt(fix(1.0 - cosa * cosa)); AB = AB * (ra / dis); @@ -150,7 +160,7 @@ bool intersect(const point &A, flt ra, const point &B, flt rb, point &P, point & bool intersect(const point &A, const point &B, const point &O, flt r, point &P, point &Q) { point AB(B - A), AO(O - A); flt dis = fabs(AB.det(AO)) / AB.norm(); - if(sgn(dis - r) > 0) return false; + if (sgn(dis - r) > 0) return false; point M = A + AB * (AB.dot(AO) / AB.norm2()); dis = sqrt(fix(r * r - dis * dis)); AB = AB / AB.norm() * dis; diff --git "a/\345\233\276\350\256\272/2-Sat.cpp" b/Graph/2-Sat.cpp similarity index 100% rename from "\345\233\276\350\256\272/2-Sat.cpp" rename to Graph/2-Sat.cpp diff --git "a/\345\233\276\350\256\272/BipolarOrientation.cpp" b/Graph/BipolarOrientation.cpp similarity index 100% rename from "\345\233\276\350\256\272/BipolarOrientation.cpp" rename to Graph/BipolarOrientation.cpp diff --git "a/\345\233\276\350\256\272/Centroid-Decomposition.cpp" b/Graph/Centroid-Decomposition.cpp similarity index 97% rename from "\345\233\276\350\256\272/Centroid-Decomposition.cpp" rename to Graph/Centroid-Decomposition.cpp index f5390d9..69c28ed 100644 --- "a/\345\233\276\350\256\272/Centroid-Decomposition.cpp" +++ b/Graph/Centroid-Decomposition.cpp @@ -31,7 +31,7 @@ namespace CentroidDecomposition { int solve(int root) { calc_size(root, -1); - PII center = MP(inf, -1); + PII center = MP(1e9, -1); find_center(root, -1, siz[root], center); vis[center.se] = true; for(auto e:adj[center.se]) { diff --git "a/\345\233\276\350\256\272/Chordal-Graph.cpp" b/Graph/Chordal-Graph.cpp similarity index 100% rename from "\345\233\276\350\256\272/Chordal-Graph.cpp" rename to Graph/Chordal-Graph.cpp diff --git "a/\345\233\276\350\256\272/Dinic.cpp" b/Graph/Dinic.cpp similarity index 100% rename from "\345\233\276\350\256\272/Dinic.cpp" rename to Graph/Dinic.cpp diff --git "a/\345\233\276\350\256\272/Dominator-Tree.cpp" b/Graph/Dominator-Tree.cpp similarity index 100% rename from "\345\233\276\350\256\272/Dominator-Tree.cpp" rename to Graph/Dominator-Tree.cpp diff --git "a/\345\233\276\350\256\272/Edmonds-Blossom.cpp" b/Graph/Edmonds-Blossom.cpp similarity index 100% rename from "\345\233\276\350\256\272/Edmonds-Blossom.cpp" rename to Graph/Edmonds-Blossom.cpp diff --git "a/\345\233\276\350\256\272/Euler-Path.cpp" b/Graph/Euler-Path.cpp similarity index 98% rename from "\345\233\276\350\256\272/Euler-Path.cpp" rename to Graph/Euler-Path.cpp index cf8347a..5e74083 100644 --- "a/\345\233\276\350\256\272/Euler-Path.cpp" +++ b/Graph/Euler-Path.cpp @@ -76,7 +76,7 @@ namespace EulerPath { void init (int n, const vector &edges) { - REP (i, 0, n + 1) + REP (i, 0, n) adj[i].clear (); path.clear (); for (auto e:edges) { @@ -95,6 +95,7 @@ namespace EulerPath { for (auto e:edges) { n = max (n, max (e.first, e.second)); } + n++; init (n, edges); int source = getSource (n, edges[0].first); find_path (source); diff --git "a/\345\233\276\350\256\272/Graph-Center.cpp" b/Graph/Graph-Center.cpp similarity index 100% rename from "\345\233\276\350\256\272/Graph-Center.cpp" rename to Graph/Graph-Center.cpp diff --git "a/\345\233\276\350\256\272/Heavy-Light-Decomposition.cpp" b/Graph/Heavy-Light-Decomposition.cpp similarity index 94% rename from "\345\233\276\350\256\272/Heavy-Light-Decomposition.cpp" rename to Graph/Heavy-Light-Decomposition.cpp index 2b8a16a..a1657d5 100644 --- "a/\345\233\276\350\256\272/Heavy-Light-Decomposition.cpp" +++ b/Graph/Heavy-Light-Decomposition.cpp @@ -12,6 +12,11 @@ namespace HLD { int dfnToID[maxn], dfn[maxn], head[maxn], fa[maxn], size[maxn], heavy[maxn], r[maxn], cnt = 1; ll dep[maxn]; + void addEdge (int u, int v, int len = 1) { + adj[u].emplace_back (v, len); + adj[v].emplace_back (u, len); + } + void firstDfs(int cur, int _fa) { size[cur] = 1; fa[cur] = _fa; diff --git a/Graph/Hungarian.cpp b/Graph/Hungarian.cpp new file mode 100644 index 0000000..6e886a9 --- /dev/null +++ b/Graph/Hungarian.cpp @@ -0,0 +1,119 @@ +#include + +using namespace std; + +template +struct hungarian { // km + int n; + vector matchx; + vector matchy; + vector pre; + vector visx; + vector visy; + vector lx; + vector ly; + vector > g; + vector slack; + T inf; + T res; + queue q; + + hungarian(int _n, int _m) { + n = max(_n, _m); + inf = numeric_limits::max(); + res = 0; + g = vector >(n, vector(n)); + matchx = vector(n, -1); + matchy = vector(n, -1); + pre = vector(n); + visx = vector(n); + visy = vector(n); + lx = vector(n, -inf); + ly = vector(n); + slack = vector(n); + } + + void addEdge(int u, int v, T w) { + assert(w >= 0); + g[u][v] = w; + } + + bool check(int v) { + visy[v] = true; + if (matchy[v] != -1) { + q.push(matchy[v]); + visx[matchy[v]] = true; + return false; + } + while (v != -1) { + matchy[v] = pre[v]; + swap(v, matchx[pre[v]]); + } + return true; + } + + void bfs(int i) { + while (!q.empty()) { + q.pop(); + } + q.push(i); + visx[i] = true; + while (true) { + while (!q.empty()) { + int u = q.front(); + q.pop(); + for (int v = 0; v < n; v++) { + if (!visy[v]) { + T delta = lx[u] + ly[v] - g[u][v]; + if (slack[v] >= delta) { + pre[v] = u; + if (delta) { + slack[v] = delta; + } else if (check(v)) { + return; + } + } + } + } + } + // 没有增广路 修改顶标 + T a = inf; + for (int j = 0; j < n; j++) { + if (!visy[j]) { + a = min(a, slack[j]); + } + } + for (int j = 0; j < n; j++) { + if (visx[j]) { // S + lx[j] -= a; + } + if (visy[j]) { // T + ly[j] += a; + } else { // T' + slack[j] -= a; + } + } + for (int j = 0; j < n; j++) { + if (!visy[j] && slack[j] == 0 && check(j)) { + return; + } + } + } + } + + void solve() { + // 初始顶标 + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + lx[i] = max(lx[i], g[i][j]); + } + } + + for (int i = 0; i < n; i++) { + fill(slack.begin(), slack.end(), inf); + fill(visx.begin(), visx.end(), false); + fill(visy.begin(), visy.end(), false); + bfs(i); + } + } +}; diff --git a/Graph/KM.cpp b/Graph/KM.cpp new file mode 100644 index 0000000..391d019 --- /dev/null +++ b/Graph/KM.cpp @@ -0,0 +1,73 @@ +// 二分图最 "大" 权 "完美" 匹配,从 0 开始 +// 不存在的边设成-inf +// sy[i] 表示 *右侧* 的 i 的对象 +struct KM { + typedef long long cost_t; + static const int N = 1000; + static constexpr cost_t inf = 1e9; + cost_t lx[N], ly[N], sl[N]; + int px[N], py[N], sy[N], fa[N], n; + + void aug (int v) { + sy[v] = py[v]; + if (px[sy[v]] != -2) aug (px[sy[v]]); + } + + bool find (int v, const cost_t w[][N]) { + for (int i = 0; i < n; ++i) + if (!~py[i]) { + if (sl[i] > lx[v] + ly[i] - w[v][i]) { + sl[i] = lx[v] + ly[i] - w[v][i]; + fa[i] = v; + } + if (lx[v] + ly[i] == w[v][i]) { + py[i] = v; + if (!~sy[i]) { + aug (i); + return 1; + } + if (~px[sy[i]]) continue; + px[sy[i]] = i; + if (find (sy[i], w)) return 1; + } + } + return 0; + } + + cost_t gao (int _n, const cost_t w[][N], cost_t m = inf) { + n = _n; + std::fill (sy, sy + n, -1); + std::fill (ly, ly + n, 0); + for (int i = 0; i < n; ++i) lx[i] = *std::max_element (w[i], w[i] + n); + for (int i (0), flag; i < n; ++i) { + for (int j = 0; j < n; ++j)px[j] = py[j] = -1, sl[j] = inf; + px[i] = -2; + if (find (i, w)) continue; + for (flag = 0, m = inf; !flag; m = inf) { + for (int j = 0; j < n; ++j) if (!~py[j]) m = std::min (m, sl[j]); + for (int j = 0; j < n; ++j) { + if (~px[j]) lx[j] -= m; + if (~py[j]) ly[j] += m; + else sl[j] -= m; + } + for (int j = 0; j < n; ++j) + if (!~py[j] && !sl[j]) { + py[j] = fa[j]; + if (!~sy[j]) { + aug (j); + flag = 1; + break; + } + px[sy[j]] = j; + if (find (sy[j], w)) { + flag = 1; + break; + } + } + } + } + cost_t ret (0); + for (int i = 0; i < n; ++i) ret += w[sy[i]][i]; + return ret; + } +} km; diff --git "a/\345\233\276\350\256\272/Kirchoff-Matrix-Tree.cpp" b/Graph/Kirchoff-Matrix-Tree.cpp similarity index 100% rename from "\345\233\276\350\256\272/Kirchoff-Matrix-Tree.cpp" rename to Graph/Kirchoff-Matrix-Tree.cpp diff --git "a/\345\233\276\350\256\272/LCA.cpp" b/Graph/LCA.cpp similarity index 100% rename from "\345\233\276\350\256\272/LCA.cpp" rename to Graph/LCA.cpp diff --git "a/\345\233\276\350\256\272/Max-Clique.cpp" b/Graph/Max-Clique.cpp similarity index 100% rename from "\345\233\276\350\256\272/Max-Clique.cpp" rename to Graph/Max-Clique.cpp diff --git "a/\345\233\276\350\256\272/Min-Cost-Flow.cpp" b/Graph/Min-Cost-Flow.cpp similarity index 100% rename from "\345\233\276\350\256\272/Min-Cost-Flow.cpp" rename to Graph/Min-Cost-Flow.cpp diff --git "a/\345\233\276\350\256\272/Mininum-Arborescence.cpp" b/Graph/Mininum-Arborescence.cpp similarity index 100% rename from "\345\233\276\350\256\272/Mininum-Arborescence.cpp" rename to Graph/Mininum-Arborescence.cpp diff --git "a/\345\233\276\350\256\272/StoerWagner.cpp" b/Graph/StoerWagner.cpp similarity index 100% rename from "\345\233\276\350\256\272/StoerWagner.cpp" rename to Graph/StoerWagner.cpp diff --git "a/\345\233\276\350\256\272/Tarjan BCC.cpp" b/Graph/Tarjan BCC.cpp similarity index 100% rename from "\345\233\276\350\256\272/Tarjan BCC.cpp" rename to Graph/Tarjan BCC.cpp diff --git "a/\345\233\276\350\256\272/Tarjan SCC.cpp" b/Graph/Tarjan SCC.cpp similarity index 100% rename from "\345\233\276\350\256\272/Tarjan SCC.cpp" rename to Graph/Tarjan SCC.cpp diff --git "a/Graph/\345\271\277\344\271\211\345\234\206\346\226\271\346\240\221.cpp" "b/Graph/\345\271\277\344\271\211\345\234\206\346\226\271\346\240\221.cpp" new file mode 100644 index 0000000..25ab93e --- /dev/null +++ "b/Graph/\345\271\277\344\271\211\345\234\206\346\226\271\346\240\221.cpp" @@ -0,0 +1,90 @@ +#include + + +namespace CircleSquareTree { + using ll = long long; + using VLL = std::vector; + + struct Edge { + ll from, to, id; + + Edge(ll from, ll to, ll id) : from(from), to(to), id(id) {} + }; + + + const ll N = 500010 * 2; //开两倍 + + ll low[N], dfn[N], cnt = 1, square; + std::vector adj[N]; + std::vector stack; + + VLL realAdj[N]; // 点双树边 + + void addRealEdge(int a, int b) { + realAdj[a].push_back(b); + realAdj[b].push_back(a); + } + + void addEdge(int a, int b, int id) { + adj[a].emplace_back(a, b, id); + adj[b].emplace_back(b, a, id); + } + + void tarjan(ll cur, Edge edge) { + dfn[cur] = low[cur] = cnt++; + for (auto e: adj[cur]) { + if (e.id != edge.id) { + auto to = e.to; + if (!dfn[to]) { + stack.push_back(e); + tarjan(to, e); + upmin(low[cur], low[to]); + if (low[to] >= dfn[cur]) { + std::vector components; + while (true) { + auto cur = stack.back(); + stack.pop_back(); + components.push_back(cur); + if (cur.id == e.id)break; + } + if (components.size() == 1) { + // bridge + addRealEdge(cur, e.to); + } else { + // bcc + auto center = square++; + for (auto edge: components) { + addRealEdge(center, edge.from); + addRealEdge(center, edge.to); + } + } + } + } else { + upmin(low[cur], dfn[to]); + } + } + } + } + + // 圆方树在realAdj,编号为 [1,square) + void run(int n, std::vector edges) { + fill(low, low + n + 1, 0); + fill(dfn, dfn + n + 1, 0); + cnt = 1, square = n + 1; + REP(i, 0, (n + 1) * 2) + adj[i].clear(); + REP(i, 0, (n + 1) * 2) + realAdj[i].clear(); + stack.clear(); + REP(i, 0, sz(edges)) + { + addEdge(edges[i].fi, edges[i].se, i); + } + tarjan(1, Edge(0, 0, -1)); + REP(i, 1, square) + { + sort(all(realAdj[i])); + complete_unique(realAdj[i]); + } + } +} diff --git "a/\346\225\260\345\255\246/Basic-Maths.cpp" b/Maths/Basic-Maths.cpp similarity index 100% rename from "\346\225\260\345\255\246/Basic-Maths.cpp" rename to Maths/Basic-Maths.cpp diff --git "a/\346\225\260\345\255\246/BerlekampMassey.cpp" b/Maths/BerlekampMassey.cpp similarity index 100% rename from "\346\225\260\345\255\246/BerlekampMassey.cpp" rename to Maths/BerlekampMassey.cpp diff --git "a/\346\225\260\345\255\246/Binomial-Coefficient.cpp" b/Maths/Binomial-Coefficient.cpp similarity index 100% rename from "\346\225\260\345\255\246/Binomial-Coefficient.cpp" rename to Maths/Binomial-Coefficient.cpp diff --git "a/\346\225\260\345\255\246/Congruence-Equation.cpp" b/Maths/Congruence-Equation.cpp similarity index 100% rename from "\346\225\260\345\255\246/Congruence-Equation.cpp" rename to Maths/Congruence-Equation.cpp diff --git "a/\346\225\260\345\255\246/Discrete-Log.cpp" b/Maths/Discrete-Log.cpp similarity index 100% rename from "\346\225\260\345\255\246/Discrete-Log.cpp" rename to Maths/Discrete-Log.cpp diff --git "a/\346\225\260\345\255\246/ExGCD.cpp" b/Maths/ExGCD.cpp similarity index 100% rename from "\346\225\260\345\255\246/ExGCD.cpp" rename to Maths/ExGCD.cpp diff --git "a/\346\225\260\345\255\246/FWT.cpp" b/Maths/FWT.cpp similarity index 100% rename from "\346\225\260\345\255\246/FWT.cpp" rename to Maths/FWT.cpp diff --git "a/\346\225\260\345\255\246/Fast-Fourier-Transform.cpp" b/Maths/Fast-Fourier-Transform.cpp similarity index 73% rename from "\346\225\260\345\255\246/Fast-Fourier-Transform.cpp" rename to Maths/Fast-Fourier-Transform.cpp index 09a5561..516b196 100644 --- "a/\346\225\260\345\255\246/Fast-Fourier-Transform.cpp" +++ b/Maths/Fast-Fourier-Transform.cpp @@ -2,11 +2,11 @@ namespace fft { const int N = 1<<20, M = 31768; struct Complex { - double x, y; + long double x, y; Complex () { x = y = 0; } - Complex (double _x, double _y) { x = _x, y = _y; } + Complex (long double _x, long double _y) { x = _x, y = _y; } Complex operator+ (const Complex &r) const { return Complex (x + r.x, y + r.y); @@ -16,11 +16,11 @@ namespace fft { return Complex (x - r.x, y - r.y); } - Complex operator* (const double k) const { + Complex operator* (const long double k) const { return Complex (x * k, y * k); } - Complex operator/ (const double k) const { + Complex operator/ (const long double k) const { return Complex (x / k, y / k); } @@ -38,14 +38,14 @@ namespace fft { } }; - const double pi = acos (-1.0); + const long double pi = std::numbers::pi; Complex w[N]; int rev[N]; void init (int L) { int n = 1<>1]>>1) | ((i & 1)<<(L - 1)); } @@ -77,34 +77,11 @@ namespace fft { Complex A[N], B[N], C1[N], C2[N]; - std::vector conv (const std::vector &a, const std::vector &b) { - int n = a.size (), m = b.size (), L = 0, s = 1; - while (s <= n + m - 2) s <<= 1, ++L; - init (L); - for (int i = 0; i < s; ++i) { - A[i] = i < n ? Complex (a[i], 0) : Complex (); - B[i] = i < m ? Complex (b[i], 0) : Complex (); - } - trans (A, s, 1); - trans (B, s, 1); - for (int i = 0; i < s; ++i) { - A[i] = A[i] * B[i]; - } - for (int i = 0; i < s; ++i) { - w[i] = w[i].conj (); - } - trans (A, s, -1); - std::vector res (n + m - 1); - for (int i = 0; i < n + m - 1; ++i) { - res[i] = (ll) (A[i].x + 0.5); - } - return res; - } - std::vector fast_conv (const std::vector &a, const std::vector &b) { + VLL conv (const VI &a, const VI &b) { int n = a.size (), m = b.size (), L = 0, s = 1; for (; s <= n + m - 2; s <<= 1, ++L); - s >>= 1, --L; + if (L > 2) s >>= 1, --L; init (L); for (int i = 0; i < s; ++i) { A[i].x = (i<<1) < n ? a[i<<1] : 0; @@ -119,9 +96,9 @@ namespace fft { C1[i] = (Complex (4, 0) * (A[j] * B[j]).conj () - (A[j].conj () - A[i]) * (B[j].conj () - B[i]) * (w[i] + Complex (1, 0))) * Complex (0, 0.25); } - std::reverse (w + 1, w + s); + reverse (w + 1, w + s); trans (C1, s, -1); - std::vector res (n + m); + VLL res (n + m); for (int i = 0; i <= (n + m - 1) / 2; ++i) { res[i<<1] = ll (C1[i].y + 0.5); res[i<<1 | 1] = ll (C1[i].x + 0.5); @@ -130,14 +107,13 @@ namespace fft { return res; } - // arbitrary modulo convolution - void conv (int a[], int b[], int n, int m, int mod, int res[]) { + VI conv (const VI &a, const VI &b, const int n, const int m, const int mod) { int s = 1, L = 0; while (s <= n + m - 2) s <<= 1, ++L; init (L); for (int i = 0; i < s; ++i) { - A[i] = i < n ? Complex (a[i] / M, a[i] % M) : Complex (); - B[i] = i < m ? Complex (b[i] / M, b[i] % M) : Complex (); + A[i] = i < n ? Complex (MOD (a[i], mod) / M, MOD (a[i], mod) % M) : Complex (); + B[i] = i < m ? Complex (MOD (b[i], mod) / M, MOD (b[i], mod) % M) : Complex (); } trans (A, s, 1); trans (B, s, 1); @@ -154,6 +130,7 @@ namespace fft { } trans (C1, s, -1); trans (C2, s, -1); + VI res (n + m - 1); for (int i = 0; i < n + m - 1; ++i) { int x = ll (C1[i].x + 0.5) % mod; int y1 = ll (C1[i].y + 0.5) % mod; @@ -161,5 +138,6 @@ namespace fft { int z = ll (C2[i].y + 0.5) % mod; res[i] = ((ll) x * M * M + (ll) (y1 + y2) * M + z) % mod; } + return res; } } diff --git "a/\346\225\260\345\255\246/Fraction.cpp" b/Maths/Fraction.cpp similarity index 100% rename from "\346\225\260\345\255\246/Fraction.cpp" rename to Maths/Fraction.cpp diff --git a/Maths/Gaussian-Elimination.cpp b/Maths/Gaussian-Elimination.cpp new file mode 100644 index 0000000..22b079f --- /dev/null +++ b/Maths/Gaussian-Elimination.cpp @@ -0,0 +1,61 @@ +typedef double flt; +const int MAXN = 64; +const flt eps = 1e-8; + +bool gauss(flt a[][MAXN], flt b[], int n) { + for (int k = 0, i, j, s; k < n; ++k) { + for (s = k, i = k + 1; i < n; ++i) + if (fabs(a[i][k]) > fabs(a[s][k]))s = i; + if (fabs(a[s][k]) < eps)return false; + if (s != k) { + std::swap(b[s], b[k]); + for (i = k; i < n; ++i) std::swap(a[s][i], a[k][i]); + } + for (j = k + 1; j < n; ++j) { + flt t = -a[j][k] / a[k][k]; + b[j] += b[k] * t; + for (i = k + 1; i < n; ++i)a[j][i] += t * a[k][i]; + } + } + for (int i = n - 1; i >= 0; --i) { + b[i] /= a[i][i]; + for (int j = 0; j < i; ++j)b[j] -= a[j][i] * b[i]; + } + return 1; +} + + +// mod 可为合数 +int det_mod (const int n, const int mod, vector> mat) { + assert(mod > 0); + assert(sz (mat) == n and sz (mat[0]) == n); + for (auto &row:mat) + for (auto &elem:row) + elem = MOD (elem, mod); + ll ret = 1; + for (int col = 0; col < n; col++) { + for (int row = col + 1; row < n; row++) { + if (mat[row][col]) { + int co = inverse (mat[row][col] / gcd (mat[row][col], mod), mod); + if (co != 1) { + for (auto &v:mat[row]) { + v = (ll) v * co % mod; + } + ret = ret * inverse (co, mod) % mod; + } + while (mat[row][col] != 0) { + ll t = mat[col][col] / mat[row][col]; + if (t) + for (int k = col; k < n; ++k) { + mat[col][k] = MOD (mat[col][k] - mat[row][k] * t, mod); + } + swap (mat[col], mat[row]); + ret *= -1; + } + } + } + ret *= mat[col][col]; + ret %= mod; + } + return MOD (ret, mod); +} diff --git "a/\346\225\260\345\255\246/Lattice-Counting.cpp" b/Maths/Lattice-Counting.cpp similarity index 100% rename from "\346\225\260\345\255\246/Lattice-Counting.cpp" rename to Maths/Lattice-Counting.cpp diff --git "a/\346\225\260\345\255\246/Matrix.cpp" b/Maths/Matrix.cpp similarity index 98% rename from "\346\225\260\345\255\246/Matrix.cpp" rename to Maths/Matrix.cpp index cad8b77..fba146f 100644 --- "a/\346\225\260\345\255\246/Matrix.cpp" +++ b/Maths/Matrix.cpp @@ -1,3 +1,4 @@ +template struct matrix { //add mod at last if there is negative number vector v; diff --git "a/\346\225\260\345\255\246/Mod-Int.cpp" b/Maths/Mod-Int.cpp similarity index 100% rename from "\346\225\260\345\255\246/Mod-Int.cpp" rename to Maths/Mod-Int.cpp diff --git "a/\346\225\260\345\255\246/Pollard-Rho&MillerRabin.cpp" b/Maths/Pollard-Rho&MillerRabin.cpp similarity index 57% rename from "\346\225\260\345\255\246/Pollard-Rho&MillerRabin.cpp" rename to Maths/Pollard-Rho&MillerRabin.cpp index 14f6e60..9e3efd0 100644 --- "a/\346\225\260\345\255\246/Pollard-Rho&MillerRabin.cpp" +++ b/Maths/Pollard-Rho&MillerRabin.cpp @@ -3,12 +3,12 @@ struct Primality { using pii = std::pair; template - T gcd(T a, T b) { - return !b ? a : gcd(b, a % b); + T gcd (T a, T b) { + return !b ? a : gcd (b, a % b); } - inline int64 mul_mod(int64 a, int64 b, int64 mod) { - if (mod < int(1e9)) return a * b % mod; + inline int64 mul_mod (int64 a, int64 b, int64 mod) { + if (mod < int (1e9)) return a * b % mod; int64 k = (int64) ((long double) a * b / mod); int64 res = a * b - k * mod; res %= mod; @@ -16,55 +16,55 @@ struct Primality { return res; } - int64 pow_mod(int64 a, int64 n, int64 m) { + int64 pow_mod (int64 a, int64 n, int64 m) { int64 res = 1; for (a %= m; n; n >>= 1) { - if (n & 1) res = mul_mod(res, a, m); - a = mul_mod(a, a, m); + if (n & 1) res = mul_mod (res, a, m); + a = mul_mod (a, a, m); } return res; } public: // 用miller rabin素数测试判断n是否为质数 - bool is_prime(int64 n) { + bool is_prime (int64 n) { if (n <= 1) return false; if (n <= 3) return true; - if (~n & 1) return false; - const int u[] = {2, 3, 5, 7, 325, 9375, 28178, 450775, 9780504, 1795265022, 0}; + if (n % 2 == 0)return false; + const int u[] = {2, 325, 9375, 28178, 450775, 9780504, 1795265022, 0}; int64 e = n - 1, a, c = 0; // 原理:http://miller-rabin.appspot.com/ - while (~e & 1) e >>= 1, ++c; + while (!(e & 1)) e >>= 1, ++c; for (int i = 0; u[i]; ++i) { - if (n <= u[i]) return true; - a = pow_mod(u[i], e, n); + if (u[i] % n == 0) continue; + a = pow_mod (u[i], e, n); if (a == 1) continue; for (int j = 1; a != n - 1; ++j) { if (j == c) return false; - a = mul_mod(a, a, n); + a = mul_mod (a, a, n); } } return true; } // 求一个小于n的因数,期望复杂度为O(n^0.25),当n为非合数时返回n本身 - int64 pollard_rho(int64 n) { - if (n <= 3 || is_prime(n)) return n; // 保证n为合数时可去掉这行 + int64 pollard_rho (int64 n) { + if (n <= 3 || is_prime (n)) return n; // 保证n为合数时可去掉这行 while (1) { int i = 1, cnt = 2; - int64 x = rand() % n, y = x, c = rand() % n; + int64 x = rand () % n, y = x, c = rand () % n; if (!c || c == n - 2) ++c; do { - int64 u = gcd(n - x + y, n); + int64 u = gcd (n - x + y, n); if (u > 1 && u < n) return u; if (++i == cnt) y = x, cnt <<= 1; - x = (c + mul_mod(x, x, n)) % n; + x = (c + mul_mod (x, x, n)) % n; } while (x != y); } return n; } // 使用rho方法对n做质因数分解,建议先筛去小质因数后再用此函数 - std::vector factorize(int64 n) { + std::vector factorize (int64 n) { static const int sp[25] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97}; std::vector fac; @@ -72,41 +72,41 @@ struct Primality { if (n % sp[i]) continue; int c = 0; while (n % sp[i] == 0) n /= sp[i], ++c; - fac.emplace_back(sp[i], c); + fac.emplace_back (sp[i], c); } std::vector u; - if (n > 1) u.push_back(n); - for (size_t i = 0; i < u.size(); ++i) { - int64 x = pollard_rho(u[i]); + if (n > 1) u.push_back (n); + for (size_t i = 0; i < u.size (); ++i) { + int64 x = pollard_rho (u[i]); if (x == u[i]) continue; u[i--] /= x; - u.push_back(x); + u.push_back (x); } - std::sort(u.begin(), u.end()); - for (size_t i = 0, j, m = u.size(); i < m; i = j) { + std::sort (u.begin (), u.end ()); + for (size_t i = 0, j, m = u.size (); i < m; i = j) { for (j = i; j < m && u[i] == u[j]; ++j); - fac.emplace_back(u[i], j - i); + fac.emplace_back (u[i], j - i); } return fac; } - std::vector divisors(int64 n) { + std::vector divisors (int64 n) { if (n == 1) return {1}; - auto fac = factorize(n); - int m = fac.size(); + auto fac = factorize (n); + int m = fac.size (); std::vector ds; - std::function dfs = [&](int d, int64 now) { + std::function dfs = [&] (int d, int64 now) { if (d == m) { - ds.emplace_back(now); + ds.emplace_back (now); return; } for (int i = 0, u = fac[d].second; i <= u; ++i) { - dfs(d + 1, now); + dfs (d + 1, now); now *= fac[d].first; } }; - dfs(0, 1); - std::sort(ds.begin(), ds.end()); + dfs (0, 1); + std::sort (ds.begin (), ds.end ()); return ds; } } pf; diff --git "a/\346\225\260\345\255\246/Polynomial-Interpolation.cpp" b/Maths/Polynomial-Interpolation.cpp similarity index 67% rename from "\346\225\260\345\255\246/Polynomial-Interpolation.cpp" rename to Maths/Polynomial-Interpolation.cpp index cc863b7..16bda24 100644 --- "a/\346\225\260\345\255\246/Polynomial-Interpolation.cpp" +++ b/Maths/Polynomial-Interpolation.cpp @@ -4,11 +4,11 @@ template std::vector interpolation(const T x[], const T y[], int n) { std::vector u(y, y + n), ret(n), sum(n); ret[0] = u[0], sum[0] = 1; - for (int i = 1; i < n; ++i) { - for (int j = n - 1; j >= i; --j) { + for(int i = 1; i < n; ++i) { + for(int j = n - 1; j >= i; --j) { u[j] = (u[j] - u[j - 1]) / (x[j] - x[j - i]); } - for (int j = i; j; --j) { + for(int j = i; j; --j) { sum[j] = -sum[j] * x[i - 1] + sum[j - 1]; ret[j] += sum[j] * u[i]; } @@ -20,13 +20,13 @@ std::vector interpolation(const T x[], const T y[], int n) { // f(x) is degree m - 1, given f(0), f(1), ..., f(m - 1), // return f(n) in linear time -ll evaluate(const std::vector &f, ll n, ll mod) { - for(auto&i:f) i = MOD(i,mod); +ll evaluate(std::vector &f, ll n, ll mod) { + for(auto &i: f) i = MOD(i, mod); ll m = f.size(), nn = n % mod; - if (n < m) return f[n]; + if(n < m) return f[n]; std::vector inv(m + 1), fact(m + 1), ifact(m + 1); inv[1] = fact[0] = ifact[0] = fact[1] = ifact[1] = 1; - for (int i = 2; i <= m; ++i) { + for(int i = 2; i <= m; ++i) { inv[i] = ll(mod - mod / i) * inv[mod % i] % mod; fact[i] = (ll) i * fact[i - 1] % mod; ifact[i] = (ll) inv[i] * ifact[i - 1] % mod; @@ -34,32 +34,32 @@ ll evaluate(const std::vector &f, ll n, ll mod) { ll ret = 0, v = 1; std::vector s(m + 1); s[m] = 1; - for (int i = m - 1; i >= 0; --i) { + for(int i = m - 1; i >= 0; --i) { v = (ll) v * (nn - i + mod) % mod; s[i] = (ll) s[i + 1] * (nn - i + mod) % mod; - if (i == nn) s[i] = 1; + if(i == nn) s[i] = 1; } - v = pow_mod(v, mod - 2, mod); - for (int i = 0; i < m; ++i) { + v = inverse(v, mod); + for(int i = 0; i < m; ++i) { ll inv2 = (ll) v * s[i + 1] % mod; v = (ll) v * (nn - i + mod) % mod; ll mul = (ll) ifact[i] * ifact[m - 1 - i] % mod * inv2 % mod; - if ((m - 1 - i) & 1) mul = mod - mul; - if (i != nn) { + if((m - 1 - i) & 1) mul = mod - mul; + if(i != nn) { ret += f[i] * mul % mod; } - if (ret >= mod) ret -= mod; + if(ret >= mod) ret -= mod; } - for (int i = 0; i < m; ++i) { + for(int i = 0; i < m; ++i) { ret = (ll) ret * (nn - i + mod) % mod; } - if (nn <= m - 1) { + if(nn <= m - 1) { ll extra = f[nn] * ifact[nn] % mod * ifact[m - 1 - nn] % mod; - if ((m - 1 - nn) & 1) extra = mod - extra; - for (int i = 0; i < m; ++i) { - if (i != nn) extra = extra * (nn - i + mod) % mod; + if((m - 1 - nn) & 1) extra = mod - extra; + for(int i = 0; i < m; ++i) { + if(i != nn) extra = extra * (nn - i + mod) % mod; } ret = (ret + extra) % mod; } - return MOD(ret,mod); + return MOD(ret, mod); } diff --git a/Maths/Polynomial.cpp b/Maths/Polynomial.cpp new file mode 100644 index 0000000..630dffd --- /dev/null +++ b/Maths/Polynomial.cpp @@ -0,0 +1,287 @@ + +namespace NTT { + const int mod = 998244353, g = 3; + // 1004535809 3 + // 1005060097 5 + // 167772161 3 + // 469762049 3 + // 924844033 5 + // 104857601 3 + void bit_reverse_swap (VI &a) { + int n = sz (a); + for (int i = 1, j = n>>1, k; i < n - 1; i++) { + if (i < j) swap (a[i], a[j]); + for (k = n>>1; j >= k; j -= k, k >>= 1); + j += k; + } + } + + void NTT (VI &a, int type) { + bit_reverse_swap (a); + int n = sz (a); + for (int i = 2; i <= n; i *= 2) { + const auto wi = fast (g, type * (mod - 1) / i, mod); // fp(g, (mod - 1) / i) 是 i 次单位根 + for (int j = 0; j < n; j += i) { + ll w = 1; + for (int k = j, h = i / 2; k < j + h; k++) { + int t = w * a[k + h] % mod, u = a[k]; + a[k] = (u + t) % mod; + a[k + h] = (u - t + mod) % mod; + w = w * wi % mod; + } + } + } + const ll inv = inverse (n, mod); + if (type == -1) for (auto &x : a) x = x * inv % mod; + } + + + VI conv (const VI &a, const VI &b, const int n, const int m, const int mod = NTT::mod) { + VI _a (begin (a), begin (a) + n); + VI _b (begin (b), begin (b) + m); + int len = 1; + while (len <= n + m - 2) len <<= 1; + while (len != lowbit (len)) len += lowbit (len); + _a.resize (len), _b.resize (len); + NTT (_a, 1), NTT (_b, 1); + REP (i, 0, len) + _a[i] = (ll) _a[i] * _b[i] % mod; + NTT (_a, -1); + _a.resize (n + m - 1); + return _a; + } +} + + +namespace Poly { + using NTT::mod; + using NTT::conv; + VI iv ({0, 1}), fac ({1, 1}), facinv ({1, 1}); + + void init (const int n) { + while (sz (iv) <= n) { + ll cur = sz (iv); + iv.emplace_back ((mod - (ll) mod / cur * iv[mod % cur] % mod)); + fac.PB (cur * fac.back () % mod); + facinv.PB ((ll) iv.back () * facinv.back () % mod); + } + } + + //B(x) ≡ 2C(x) − A(x)C(x)^2 + VI inv (const VI &poly) { + int n = 1; + VI res (1); + res[0] = inverse (poly[0], mod); + while (n < sz (poly)) { + auto new_res = conv (res, res, n, n, mod); + new_res = conv (poly, new_res, min (2 * n, sz (poly)), sz (new_res), mod); + res.resize (2 * n, 0); + REP (i, 0, 2 * n) { + res[i] = (2ll * res[i] - (i < sz (new_res) ? new_res[i] : 0) + mod) % mod; + } + n *= 2; + } + res.resize (sz (poly)); + return res; + } + + VI integrate (const VI &poly) { + init (sz (poly)); + VI res (sz (poly), 0); + REP (i, 1, sz (res)) { + res[i] = poly[i - 1] * (ll) iv[i] % mod; + } + return res; + } + + VI differentiate (const VI &poly) { + VI res (sz (poly), 0); + REP (i, 0, sz (res) - 1) { + res[i] = poly[i + 1] * ll (i + 1) % mod; + } + return res; + } + + VI log (const VI &poly) { + auto res = integrate (conv (differentiate (poly), inv (poly), sz (poly), sz (poly), mod)); + res.resize (sz (poly)); + return res; + } + + // g ≡ (1 − ln(g0) + f)g0 + VI exp (const VI &poly) { + int n = 1; + VI res (1, 1); + VI tmp; + while (n < sz (poly)) { + tmp = res; + tmp.resize (2 * n, 0); + tmp = log (tmp); + REP (i, 0, 2 * n) { + tmp[i] = (ll (i == 0) - tmp[i] + (i < sz (poly) ? poly[i] : 0) + mod) % mod; + } + res = conv (res, tmp, n, 2 * n, mod); + res.resize (2 * n, 0); + n *= 2; + } + res.resize (sz (poly)); + return res; + } + + // k < mod + VI power (const VI &poly, const ll k) { + auto low = find_if (all (poly), [] (const int x) { return x != 0; }); + if (low == end (poly))return VI (sz (poly), 0); + ll padding = (low - begin (poly)) * k; + if (padding >= sz (poly))return VI (sz (poly), 0); + VI tmp (low, end (poly)); + ll inv = inverse (*low, mod); + for (auto &x:tmp) x = x * inv % mod; + tmp = log (tmp); + for (auto &x:tmp) x = x * (k % mod) % mod; + tmp = exp (tmp); + ll pw = fast (inv, -k, mod); + for (auto &x:tmp) x = x * pw % mod; + if (padding) { + VI zeros (padding, 0); + tmp.insert (tmp.begin (), all (zeros)); + } + tmp.resize (sz (poly), 0); + return tmp; + } + + ll modSqrt (ll a, ll p) { + auto isSquare = [&] (ll a, ll p) { + return fast (a, (p - 1) / 2, p) == 1; + }; + if (a == 0) return 0; + if (p == 2) return a; + if (!isSquare (a, p)) return -1; + ll b = 2; + while (isSquare ((b * b - a + p) % p, p)) b++; + ll w = (b * b - a + p) % p; + + auto mul = [&] (PLL u, PLL v) { + ll a = (u.first * v.first + u.second * v.second % p * w) % p; + ll b = (u.first * v.second + u.second * v.first) % p; + return MP (a, b); + }; + + // (b + sqrt(b^2-a))^(p+1)/2 + ll e = (p + 1) / 2; + auto ret = MP (1, 0); + auto v = MP (b, 1); + while (e > 0) { + if (e & 1) ret = mul (ret, v); + v = mul (v, v); + e /= 2; + } + return ret.first; + } + + VI sqrt (VI poly) { + const int len = sz (poly); + init (2); + const auto low = find_if (all (poly), [] (const int x) { return x != 0; }); + if (low == end (poly))return VI (sz (poly), 0); + int padding = (low - begin (poly)); + if (padding & 1) return VI (1, -1); + padding >>= 1; + poly = VI (low, end (poly)); + VI res (1); + res[0] = modSqrt (poly[0], mod); + if (res[0] == -1)return res; + upmin (res[0], mod - res[0]); + int n = 1; + while (n < len) { + n *= 2; + res.resize (n, 0); + auto other = conv (poly, inv (res), min (2 * n, sz (poly)), n, mod); + REP (i, 0, n) { + res[i] = (res[i] + other[i]) * ll (iv[2]) % mod; + } + } + if (padding) { + VI zeros (padding, 0); + res.insert (res.begin (), all (zeros)); + } + res.resize (len, 0); + return res; + } + + // + pair divmod (VI f, VI g) { + auto removeTrailingZeros = [] (VI &poly) { + while (sz (poly) and poly.back () == 0)poly.pop_back (); + }; + removeTrailingZeros (f); + removeTrailingZeros (g); + assert (sz (g) > 0); + const int n = sz (f) - 1, m = sz (g) - 1; + if (n < m)return MP (VI (), f); + auto rev = [] (VI poly) { + reverse (all (poly)); + return poly; + }; + auto rg = rev (g); + rg.resize (n, 0); + auto q = (conv (rev (f), inv (rg), sz (f), sz (rg), mod)); + q.resize (n - m + 1, 0); + q = rev (q); + auto prod = conv (g, q, sz (g), sz (q), mod); + auto r = f; + REP (i, 0, sz (r))r[i] = (r[i] - prod[i] + mod) % mod; + r.resize (m, 0); + removeTrailingZeros (r); + return MP (q, r); + } + + VI shift (const VI &poly, const int n) { + init (sz (poly)); + VI a (sz (poly)), b (sz (poly)); + REP (i, 0, sz (a))a[i] = (ll) fac[i] * poly[i] % mod; + for (int i = 0, prod = 1; i < sz (poly); i++, prod = (ll) prod * n % mod) { + b[i] = (ll) facinv[i] * prod % mod; + } + VI res (sz (poly)); + reverse (all (b)); + a = conv (a, b, sz (a), sz (b), mod); + REP (i, 0, sz (res)) { + res[i] = (ll) a[i + sz (poly) - 1] * facinv[i] % mod; + } + return res; + } + + + // x(x-1)(x-2)...(x-(n-1)) + VI signedFirstStirling (const int n) { + if (n == 0) return VI ({1}); + else { + VI a = signedFirstStirling (n / 2); + VI b = shift (a, mod - n / 2); + a = conv (a, b, sz (a), sz (b), mod); + if (n & 1) { + a.PB (0); + RREP (i, n, 0) { + a[i] = (ll (a[i]) * (mod - (n - 1)) + (i > 0 ? a[i - 1] : 0)) % mod; + } + } + return a; + } + } + + VI secondStirling (const int n) { + init (n); + VI a (begin (facinv), begin (facinv) + n + 1), b (begin (facinv), begin (facinv) + n + 1); + REP(i, 0, n + 1) { + if (i & 1)b[i] = mod - b[i]; + a[i] = MOD (a[i] * fast (i, n, mod), mod); + } + auto res = conv (a, b, n + 1, n + 1, mod); + res.resize (n + 1); + return res; + } + + + // TODO: Multi Point Eval +} diff --git a/Maths/PrimeCounting.cpp b/Maths/PrimeCounting.cpp new file mode 100644 index 0000000..1746cd9 --- /dev/null +++ b/Maths/PrimeCounting.cpp @@ -0,0 +1,55 @@ +struct PrimeCounting { +private: + void EratosthenesSieve (const int n, VLL &primes) { + vector numbers (n + 1); + for (ll i = 2; i <= n; i++) { + if (!numbers[i]) { + primes.PB (i); + for (ll j = i * i; j <= n; j += i)numbers[j] = 1; + } + } + } + + void compute () { + for (auto p:primes) { + for (int i = 0; i < sz(quotient); i++) { + if (p * p > quotient[i])break; + // 卡常时如不需要 mod 可以去掉 + sum[i] = MOD (sum[i] - (sum[get_id (divisor[i] * p)] - sum[get_id ((n / (p - 1)))]), mod); + } + } + } + + inline int get_id (const ll &divisor) { + if (n / divisor <= lim) { + return id[0][n / divisor]; + } else { + return id[1][divisor]; + } + } + +public: + VI id[2]; + VLL quotient, sum, divisor, primes; + const ll lim, n, mod; + + // 传入积性函数前缀和函数 prefix_f + // 答案在 sum[0] + template + PrimeCounting (const ll n, T prefix_f, const ll mod):n (n), lim (sqrt (n)), mod (mod) { + id[0] = id[1] = VI (lim + 1, 0); + for (ll i = 1; i <= n; i = n / (n / i) + 1) { + quotient.emplace_back (n / i); + divisor.emplace_back (i); + sum.emplace_back (prefix_f (n / i)); + if (n / i <= lim) { + id[0][n / i] = sz(quotient) - 1; + } else { + id[1][i] = sz(quotient) - 1; + } + } + EratosthenesSieve (lim, primes); + compute (); + } + +}; diff --git "a/\346\225\260\345\255\246/Sieve.cpp" b/Maths/Sieve.cpp similarity index 100% rename from "\346\225\260\345\255\246/Sieve.cpp" rename to Maths/Sieve.cpp diff --git "a/\346\225\260\345\255\246/Simplex.cpp" b/Maths/Simplex.cpp similarity index 100% rename from "\346\225\260\345\255\246/Simplex.cpp" rename to Maths/Simplex.cpp diff --git "a/\346\225\260\345\255\246/Xor-Basis.cpp" b/Maths/Xor-Basis.cpp similarity index 100% rename from "\346\225\260\345\255\246/Xor-Basis.cpp" rename to Maths/Xor-Basis.cpp diff --git "a/\345\205\266\344\273\226/BigInt.cpp" b/Misc/BigInt.cpp similarity index 100% rename from "\345\205\266\344\273\226/BigInt.cpp" rename to Misc/BigInt.cpp diff --git "a/\345\205\266\344\273\226/Bit-Hacks.cpp" b/Misc/Bit-Hacks.cpp similarity index 100% rename from "\345\205\266\344\273\226/Bit-Hacks.cpp" rename to Misc/Bit-Hacks.cpp diff --git "a/\345\205\266\344\273\226/Calendar.cpp" b/Misc/Calendar.cpp similarity index 77% rename from "\345\205\266\344\273\226/Calendar.cpp" rename to Misc/Calendar.cpp index 39b1abc..bbd3246 100644 --- "a/\345\205\266\344\273\226/Calendar.cpp" +++ b/Misc/Calendar.cpp @@ -1,4 +1,4 @@ -#include "bits/stdc++.h" +#include int week(int y, int m, int d) { if (m < 3) { @@ -9,11 +9,6 @@ int week(int y, int m, int d) { return w; } -int main() { - printf("%d\n", week(2015, 4, 16)); // => 3 Thursday - printf("%d\n", week(1989, 2, 3)); // => 4 Friday - return 0; -} bool isLeap(int year) { return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0); @@ -26,3 +21,8 @@ int getDays(int year, int month) { } +int main() { + std::printf("%d\n", week(2015, 4, 16)); // => 3 Thursday + std::printf("%d\n", week(1989, 2, 3)); // => 4 Friday + return 0; +} diff --git a/Misc/n-queen special solution.cpp b/Misc/n-queen special solution.cpp new file mode 100644 index 0000000..27ffd5f --- /dev/null +++ b/Misc/n-queen special solution.cpp @@ -0,0 +1,28 @@ +#include + +int main() { + int n; + std::cin >> n; + if (n == 2 || n == 3) { + printf("-1"); + return 0; + } + if (n % 6 != 2 && n % 6 != 3) { + for (int i = 2; i <= n; i += 2)printf("%d ", i - 1); + for (int i = 1; i <= n; i += 2)printf("%d ", i - 1); + } else { + int k = n >> 1; + if (k & 1) { + for (int i = k; i <= n - 1; i += 2)printf("%d ", i - 1); + for (int i = 1; i <= k - 1; i += 2)printf("%d ", i - 1); + for (int i = k + 3; i <= n; i += 2)printf("%d ", i - 1); + for (int i = 2; i <= k + 1; i += 2)printf("%d ", i - 1); + } else { + for (int i = k; i <= n; i += 2)printf("%d ", i - 1); + for (int i = 2; i <= k - 1; i += 2)printf("%d ", i - 1);; + for (int i = k + 3; i <= n - 1; i += 2)printf("%d ", i - 1); + for (int i = 1; i <= k + 1; i += 2)printf("%d ", i - 1); + } + if (n & 1)printf("%d ", n - 1);; + } +} diff --git "a/\345\270\270\350\247\201\351\224\231\350\257\257.md" b/Pitfalls.md similarity index 62% rename from "\345\270\270\350\247\201\351\224\231\350\257\257.md" rename to Pitfalls.md index ae8b6e2..181d819 100644 --- "a/\345\270\270\350\247\201\351\224\231\350\257\257.md" +++ b/Pitfalls.md @@ -20,22 +20,6 @@ - 及时取模 - 取消同步后混用 - 二分时有负数要写 `l+(r-l)/2` - -```bash -alias gao=g++ -O2 -Wall -Wextra -pedantic -Wshadow -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC -fsanitize=address -fsanitize=undefined -``` - -``` bash -while true; do - ./generate > input - ./run < input > output - ./std < input > answer - if diff output answer; then - echo OK - else - echo WA - break - fi -done -``` +- 谨慎复制粘贴 + diff --git a/Starter/LeetCode.cpp b/Starter/LeetCode.cpp new file mode 100644 index 0000000..4261c37 --- /dev/null +++ b/Starter/LeetCode.cpp @@ -0,0 +1,169 @@ +#include +#include +#include + +#define PB push_back +#define PF push_front +#define LB lower_bound +#define UB upper_bound +#define fr(x) freopen(x,"r",stdin) +#define fw(x) freopen(x,"w",stdout) +#define REP(i, from, to) for(ll i = from;i=to;i--) +#define complete_unique(a) a.erase(unique(begin(a),end(a)),end(a)) +#define mst(x, a) memset(x,a,sizeof(x)) +#define all(a) begin(a),end(a) +#define rall(a) rbegin(a),rend(a) +#define MP make_pair +#define lowbit(x) ((x)&(-(x))) +#define bitcnt(x) (__builtin_popcountll(x)) +#define se second +#define fi first + +using ll = long long; +using ull = unsigned long long; +using db = double; +using ld = long double; +using VLL = std::vector; +using VI = std::vector; +using PII = std::pair; +using PLL = std::pair; + +using namespace __gnu_pbds; //required +using namespace std; +template using ordered_set = tree, rb_tree_tag, tree_order_statistics_node_update>; +const ll mod = 1e9 + 7; + + +string to_string(string s) { return '"' + s + '"'; } + +string to_string(const char *s) { return to_string((string) s); } + +string to_string(bool b) { return (b ? "true" : "false"); } + +template +string to_string(pair p) { return "(" + to_string(p.first) + ", " + to_string(p.second) + ")"; } + +template +string to_string(A v) { + bool first = true; + string res = "{"; + for (const auto &x: v) { + if (!first) { res += ", "; } + first = false; + res += to_string(x); + } + res += "}"; + return res; +} + +void debug_out() { cerr << endl; } + +template +void debug_out(Head H, Tail... T) { + cerr << " " << to_string(H); + debug_out(T...); +} + +#ifdef LOCAL +#define dbg(...) cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__) +#else +#define dbg(...) do {} while(0) +#endif + +template +void setmin(T &a, U b) { if (b < a) a = b; } + +template +void setmax(T &a, U b) { if (b > a) a = b; } + + +ull twop(ll x) { return 1ULL << x; } + +ll MOD(ll a, ll m) { + a %= m; + if (a < 0)a += m; + return a; +} + +ll inverse(ll a, ll m) { + a = MOD(a, m); + if (a <= 1)return a; + return MOD((1 - inverse(m, a) * m) / a, m); +} + +template +T sqr(T x) { return x * x; } + +template +ll sz(const T &x) { return x.size(); } + +ll fast(ll a, ll b, ll mod) { + a %= mod; + if (b < 0)a = inverse(a, mod), b = -b; + ll ans = 1; + while (b) { + if (b & 1)ans = ans * a % mod; + a = a * a % mod; + b /= 2; + } + return ans % mod; +} + + +#ifdef LOCAL + + +namespace SOLVE { + void main() { + + } +} + +#ifdef __APPLE__ +#define INPUT_FILE "/Users/qingczha/ClionProjects/LeetCode/input.txt" +#define OUTPUT_FILE "/Users/qingczha/ClionProjects/LeetCode/output.txt" +#elifdef _WIN64 +#define INPUT_FILE "C:/Users/qingczha/CLionProjects/playground/input.txt" +#define OUTPUT_FILE "C:/Users/qingczha/CLionProjects/playground/output.txt" +#elifdef __linux__ +#define INPUT_FILE "/home/qingczha/proj/Playground/input.txt" +#define OUTPUT_FILE "/home/qingczha/proj/Playground/output.txt" +#endif + +signed main() { + fr(INPUT_FILE); + fw(OUTPUT_FILE); + ios::sync_with_stdio(false); + cin.tie(nullptr); + cout.tie(nullptr); + + int t = 1; +// cin >> t; + for (int i = 1; i <= t; i++) { +// cout<<"Case #"< +#include +#include + +#define PB push_back +#define PF push_front +#define LB lower_bound +#define UB upper_bound +#define fr(x) freopen(x,"r",stdin) +#define fw(x) freopen(x,"w",stdout) +#define REP(i, from, to) for(ll i = from;i=to;i--) +#define complete_unique(a) a.erase(unique(begin(a),end(a)),end(a)) +#define mst(x, a) memset(x,a,sizeof(x)) +#define all(a) begin(a),end(a) +#define rall(a) rbegin(a),rend(a) +#define MP make_pair +#define lowbit(x) ((x)&(-(x))) +#define bitcnt(x) (__builtin_popcountll(x)) +#define se second +#define fi first + +using ll = long long; +using ull = unsigned long long; +using db = double; +using ld = long double; +using VLL = std::vector; +using VI = std::vector; +using PII = std::pair; +using PLL = std::pair; + +using namespace __gnu_pbds; //required +using namespace std; +template using ordered_set = tree, rb_tree_tag, tree_order_statistics_node_update>; +const ll mod = 1e9 + 7; + + +string to_string(string s) { return '"' + s + '"'; } + +string to_string(const char *s) { return to_string((string) s); } + +string to_string(bool b) { return (b ? "true" : "false"); } + +template +string to_string(pair p) { return "(" + to_string(p.first) + ", " + to_string(p.second) + ")"; } + +template +string to_string(A v) { + bool first = true; + string res = "{"; + for (const auto &x: v) { + if (!first) { res += ", "; } + first = false; + res += to_string(x); + } + res += "}"; + return res; +} + +void debug_out() { cerr << endl; } + +template +void debug_out(Head H, Tail... T) { + cerr << " " << to_string(H); + debug_out(T...); +} + +#ifdef LOCAL +#define dbg(...) cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__) +#else +#define dbg(...) do {} while(0) +#endif + +template +void setmin(T &a, U b) { if (b < a) a = b; } + +template +void setmax(T &a, U b) { if (b > a) a = b; } + + +ull twop(ll x) { return 1ULL << x; } + +ll MOD(ll a, ll m) { + a %= m; + if (a < 0)a += m; + return a; +} + +ll inverse(ll a, ll m) { + a = MOD(a, m); + if (a <= 1)return a; + return MOD((1 - inverse(m, a) * m) / a, m); +} + +template +T sqr(T x) { return x * x; } + +template +ll sz(const T &x) { return x.size(); } + +ll fast(ll a, ll b, ll mod) { + a %= mod; + if (b < 0)a = inverse(a, mod), b = -b; + ll ans = 1; + while (b) { + if (b & 1)ans = ans * a % mod; + a = a * a % mod; + b /= 2; + } + return ans % mod; +} + + +namespace SOLVE { + void main() { + + } +} + +#ifdef __APPLE__ +#define INPUT_FILE "/Users/qingczha/ClionProjects/LeetCode/input.txt" +#define OUTPUT_FILE "/Users/qingczha/ClionProjects/LeetCode/output.txt" +#elifdef _WIN64 +#define INPUT_FILE "C:/Users/qingczha/CLionProjects/playground/input.txt" +#define OUTPUT_FILE "C:/Users/qingczha/CLionProjects/playground/output.txt" +#elifdef __linux__ +#define INPUT_FILE "/home/qingczha/proj/Playground/input.txt" +#define OUTPUT_FILE "/home/qingczha/proj/Playground/output.txt" +#endif + +signed main() { +#ifdef LOCAL + fr(INPUT_FILE); + fw(OUTPUT_FILE); +#endif + ios::sync_with_stdio(false); + cin.tie(nullptr); + cout.tie(nullptr); + + int t = 1; +// cin >> t; + for (int i = 1; i <= t; i++) { +// cout<<"Case #"< +#include +#include + +void calcNext(const std::string &s, int nxt[]) { + int p = nxt[0] = -1; + for (int i = 1; i < s.size(); i++) { + while (p != -1 && s[p + 1] != s[i])p = nxt[p]; + p += s[p + 1] == s[i]; + nxt[i] = p; + } +} + + +std::vector exkmp(const std::string &s) { + int n = s.size(); + std::vector z(n); + int x = 0, y = 0; + for (int i = 1; i < n; i++) { + z[i] = std::max(0, std::min(z[i - x], y - i + 1)); + while (i + z[i] < n && s[z[i]] == s[i + z[i]]) { + x = i; + y = i + z[i]; + z[i]++; + } + } + z[0] = n; + return z; +} diff --git "a/\345\255\227\347\254\246\344\270\262/Manacher.cpp" b/String/Manacher.cpp similarity index 100% rename from "\345\255\227\347\254\246\344\270\262/Manacher.cpp" rename to String/Manacher.cpp diff --git "a/\345\255\227\347\254\246\344\270\262/Max-Suffix.cpp" b/String/Max-Suffix.cpp similarity index 100% rename from "\345\255\227\347\254\246\344\270\262/Max-Suffix.cpp" rename to String/Max-Suffix.cpp diff --git a/String/String-Hash.cpp b/String/String-Hash.cpp new file mode 100644 index 0000000..4f7dee2 --- /dev/null +++ b/String/String-Hash.cpp @@ -0,0 +1,67 @@ +// 1-based +// 支持char/int/ll +// push - 加在末尾 +// build - 重建 +// hash(l,r) - 获取 [l,r] 的 hash +struct Hashing { + array seed, mod; + array, 2> hs, pw; + + Hashing (array seed = {28, 31}, + array mod = {1000000007, 1000173169}) : seed (seed), mod (mod) { + init (); + } + + void init () { + hs[0] = hs[1] = {0}; + pw[0] = pw[1] = {1}; + } + + void push (ll ch) { + assert (ch != 0); + for (int i = 0; i < 2; i++) { + pw[i].push_back (pw[i].back () * seed[i] % mod[i]); + hs[i].push_back ((hs[i].back () * seed[i] + ch) % mod[i]); + } + } + + void pop () { + assert (size () > 1); + for (int i = 0; i < 2; i++) { + pw[i].pop_back (); + hs[i].pop_back (); + } + } + + + template + void build (T begin, T end) { + init (); + while (begin != end) { + push (*(begin++)); + } + } + + template + void push (T begin, T end) { + while (begin != end) { + push (*(begin++)); + } + } + + ll hash (int l, int r) { + l--; + assert (l <= r and r <= size ()); + array ans{0, 0}; + if (l >= r)return (ans[0]<<32) + ans[1]; + for (int i = 0; i < 2; i++) { + ans[i] = (hs[i][r] - hs[i][l] * pw[i][r - l]) % mod[i]; + if (ans[i] < 0)ans[i] += mod[i]; + } + return (ans[0]<<32) + ans[1]; + } + + int size () { + return hs[0].size () - 1; + } +}; diff --git a/String/Suffix-Array.cpp b/String/Suffix-Array.cpp new file mode 100644 index 0000000..30158f3 --- /dev/null +++ b/String/Suffix-Array.cpp @@ -0,0 +1,83 @@ +template +class SuffixArray { +public: + void build_SA (const T &str, vector &sa, vector &rk) { + + const int len = sz(str); + vector> ord[2] = {vector> (len), vector> (len)}; + sa = std::vector (len); + rk = std::vector (len); + REP(i, 0, len) { + ord[1][i] = MP (MP (str[i], 0), i); + } + for (int b = 0;; b++) { + int cur = b % 2; + sort (all(ord[cur ^ 1])); + REP(i, 0, len) { + rk[ord[cur ^ 1][i].se] = + i == 0 ? 0 : (rk[ord[cur ^ 1][i - 1].se] + (ord[cur ^ 1][i - 1].fi != ord[cur ^ 1][i].fi)); + } + if (rk[ord[cur ^ 1][len - 1].se] == len - 1)break; + REP(i, 0, len)ord[cur][i] = MP (MP (rk[i], (i + twop (b) < len) ? rk[i + twop (b)] : -1e9), i); + } + REP(i, 0, len)sa[rk[i]] = i; + } + + vector> st; + + void build_height (const T &str, const vector &sa, const vector &rk, vector &height) { + height = std::vector (sz(str), 0); + const int len = sz(str); + REP(i, 0, len) { + if (rk[i] == 0)continue; + while (i + height[rk[i]] < len && sa[rk[i] - 1] + height[rk[i]] < len && + str[i + height[rk[i]]] == str[sa[rk[i] - 1] + height[rk[i]]]) { + height[rk[i]]++; + } + if (i != len - 1) { + height[rk[i + 1]] = max (0, height[rk[i]] - 1); + } + } + } + + T str; + vector sa, rk; + + void init (const T &s, bool getHeight = 0) { + str = s; + build_SA (str, sa, rk); + if (getHeight) { + st = vector> (ceil (log2 (sz(s)) + 1e-2), vector (sz(s))); + build_height (str, sa, rk, st[0]); + REP(i, 0, sz (st) - 1) { + REP(j, 0, sz (s) - twop (i)) { + st[i + 1][j] = min (st[i][j], st[i][j + twop (i)]); + } + } + } + } + + void test () { + REP(i, 0, sz (str)) { + cout<<(i)<<" "; + REP(j, sa[i], sz (str)) { + if (str[j] < 0)break; + cout< r)swap (l, r); + l++; + int lvl = floor (log2 (r - l + 1)); + return min (st[lvl][l], st[lvl][r - twop (lvl) + 1]); + } + } + +}; diff --git "a/\345\255\227\347\254\246\344\270\262/Suffix-Automaton.cpp" b/String/Suffix-Automaton.cpp similarity index 54% rename from "\345\255\227\347\254\246\344\270\262/Suffix-Automaton.cpp" rename to String/Suffix-Automaton.cpp index 7493055..f58122b 100644 --- "a/\345\255\227\347\254\246\344\270\262/Suffix-Automaton.cpp" +++ b/String/Suffix-Automaton.cpp @@ -1,44 +1,51 @@ struct SAM { - static const int maxn = 300010 * 2; - struct node { - node *nxt[26], *fail; + static const int N = 500010 * 2, ALPHABET = 2, BASE = '0'; + struct Node { + Node *nxt[ALPHABET], *fail; int cnt; int len; }; - node *root; + Node *root; int cnt; - node no[maxn]; + Node no[N]; - node *newnode() { + Node *newNode() { + memset(&no[cnt], 0, sizeof(Node)); return &no[cnt++]; } - SAM() { + void init() { cnt = 0; - root = newnode(); + root = newNode(); + } + + SAM() { + init(); } void add(const string &s) { - node *cur = root; - REP(i, 0, sz(s)) { - cur = add(cur, s[i] - 'a'); + Node *cur = root; + REP(i, 0, sz(s)) + { + cur = add(cur, s[i]); } } - node *add(node *p, int c) { - node *cur = newnode(); + Node *add(Node *p, int c) { + c -= BASE; + Node *cur = newNode(); cur->len = p->len + 1; while(p && !p->nxt[c])p->nxt[c] = cur, p = p->fail; if(!p) { cur->fail = root; return cur; } - node *q = p->nxt[c]; + Node *q = p->nxt[c]; if(q->len == p->len + 1) { cur->fail = q; } else { - node *nq = newnode(); + Node *nq = newNode(); *nq = *q; nq->len = p->len + 1; q->fail = cur->fail = nq; @@ -48,9 +55,10 @@ struct SAM { } void pre(const string &s) { - node *cur = root; - REP(i, 0, sz(s)) { - cur = cur->nxt[s[i] - 'a']; + Node *cur = root; + REP(i, 0, sz(s)) + { + cur = cur->nxt[s[i] - BASE]; cur->cnt++; } } @@ -58,21 +66,24 @@ struct SAM { //call pre first //return sum of cnt void getCnt() { - vector v; - REP(i, 1, cnt) { + vector < Node * > v; + REP(i, 1, cnt) + { v.PB(&no[i]); } - sort(all(v), [](const node *a, const node *b) { + sort(all(v), [](const Node *a, const Node *b) { return a->len > b->len; }); - REP(i, 0, sz(v)) { + REP(i, 0, sz(v)) + { v[i]->fail->cnt += v[i]->cnt; } } ll getNumOfDistinctSubstrings() { - auto ans = 0; - REP(i, 1, cnt)ans += no[i].len - no[i].fail->len; + ll ans = 0; + REP(i, 1, cnt) + ans += no[i].len - no[i].fail->len; return (ans); } }; diff --git "a/\345\205\266\344\273\226/n-queen special solution.cpp" "b/\345\205\266\344\273\226/n-queen special solution.cpp" deleted file mode 100644 index 9868b4b..0000000 --- "a/\345\205\266\344\273\226/n-queen special solution.cpp" +++ /dev/null @@ -1,34 +0,0 @@ -#include -int main() -{ - int n; - scanf("%d",&n); - if(n == 2 || n == 3){ - printf("-1"); - return 0; - } - if (n%6!=2&&n%6!=3) - { - for(int i=2;i<=n;i+=2)printf("%d ",i-1); - for(int i=1;i<=n;i+=2)printf("%d ",i-1); - } - else - { - int k=n>>1; - if (k&1) - { - for(int i=k;i<=n-1;i+=2)printf("%d ",i-1); - for(int i=1;i<=k-1;i+=2)printf("%d ",i-1); - for(int i=k+3;i<=n;i+=2)printf("%d ",i-1); - for(int i=2;i<=k+1;i+=2)printf("%d ",i-1); - } - else - { - for(int i=k;i<=n;i+=2)printf("%d ",i-1); - for(int i=2;i<=k-1;i+=2)printf("%d ",i-1);; - for(int i=k+3;i<=n-1;i+=2)printf("%d ",i-1); - for(int i=1;i<=k+1;i+=2)printf("%d ",i-1); - } - if (n&1)printf("%d ",n-1);; - } -} diff --git "a/\345\233\276\350\256\272/Hungarian.cpp" "b/\345\233\276\350\256\272/Hungarian.cpp" deleted file mode 100644 index d3ea20d..0000000 --- "a/\345\233\276\350\256\272/Hungarian.cpp" +++ /dev/null @@ -1,46 +0,0 @@ -struct Hungarian { - std::vector vc, is;// vertex corver and independent set - std::vector pos, neg;// pos为左侧点所匹配到的右侧点编号, neg反之 - std::vector vis, mark;// 分别记录左右点的访问情况 - // 左侧点数目n, 右侧点数目m, 以及左边点到右边点的边表 - // 返回最大匹配数目, 方案存在pos和neg里面 - // vc和is记录了最小点覆盖和最大独立集的方案 - int run(int n, int m, std::vector edges[]) { - neg.assign(m, -1), pos.assign(n, -1); - mark.resize(m), vis.resize(n); - int ret = 0; - for (int i = 0; i < n; ++i) { - std::fill(mark.begin(), mark.end(), false); - std::fill(vis.begin(), vis.end(), false); - if (aug(i, edges)) ++ret; - } - std::fill(mark.begin(), mark.end(), false); - std::fill(vis.begin(), vis.end(), false); - for (int i = 0; i < n; ++i) { - if (pos[i] == -1) aug(i, edges); - } - vc.clear(), is.clear(); - for (int i = 0; i < n; ++i) { - if (!vis[i]) vc.push_back(i); - else is.push_back(i); - } - for (int i = 0; i < m; ++i) { - if (mark[i]) vc.push_back(i); - else is.push_back(i); - } - return ret; - } - - bool aug(int u, std::vector edges[]) { - vis[u] = true; - for (auto &&v: edges[u]) - if (!mark[v]) { - mark[v] = true; - if (neg[v] == -1 || aug(neg[v], edges)) { - pos[u] = v, neg[v] = u; - return true; - } - } - return false; - } -}; diff --git "a/\345\233\276\350\256\272/\345\271\277\344\271\211\345\234\206\346\226\271\346\240\221.cpp" "b/\345\233\276\350\256\272/\345\271\277\344\271\211\345\234\206\346\226\271\346\240\221.cpp" deleted file mode 100644 index 8751b05..0000000 --- "a/\345\233\276\350\256\272/\345\271\277\344\271\211\345\234\206\346\226\271\346\240\221.cpp" +++ /dev/null @@ -1,80 +0,0 @@ -namespace CircleSquareTree { - struct Edge { - ll from, to, id; - - Edge (ll from, ll to, ll id) : from (from), to (to), id (id) {} - }; - - - const ll N = 500010*2; //开两倍 - - ll low[N], dfn[N], cnt = 1, square; - vector adj[N]; - vector stack; - - VLL realAdj[N]; // 点双树边 - - void addRealEdge (int a, int b) { - realAdj[a].PB (b); - realAdj[b].PB (a); - } - - void addEdge (int a, int b, int id) { - adj[a].PB (Edge (a, b, id)); - adj[b].PB (Edge (b, a, id)); - } - - void tarjan (ll cur, Edge edge) { - dfn[cur] = low[cur] = cnt++; - for (auto e:adj[cur]) { - if (e.id != edge.id) { - auto to = e.to; - if (!dfn[to]) { - stack.PB (e); - tarjan (to, e); - upmin (low[cur], low[to]); - if (low[to] >= dfn[cur]) { - vector components; - while (true) { - auto cur = stack.back (); - stack.pop_back (); - components.PB (cur); - if (cur.id == e.id)break; - } - if (sz(components) == 1) { - // bridge - addRealEdge (cur, e.to); - } else { - // bcc - auto center = square++; - for (auto edge:components) { - addRealEdge (center, edge.from); - addRealEdge (center, edge.to); - } - } - } - } else { - upmin (low[cur], dfn[to]); - } - } - } - } - - // 圆方树在realAdj,编号为 [1,square) - void run (int n, vector edges) { - fill (low, low + n + 1, 0); - fill (dfn, dfn + n + 1, 0); - cnt = 1, square = n + 1; - REP(i, 0, (n + 1) * 2)adj[i].clear (); - REP(i, 0, (n + 1) * 2)realAdj[i].clear (); - stack.clear (); - REP(i, 0, sz (edges)) { - addEdge (edges[i].fi, edges[i].se, i); - } - tarjan (1, Edge (0, 0, -1)); - REP(i, 1, square) { - sort (all(realAdj[i])); - complete_unique(realAdj[i]); - } - } -} diff --git "a/\345\244\264\346\226\207\344\273\266\345\217\212\346\265\213\350\257\225/Template.cpp" "b/\345\244\264\346\226\207\344\273\266\345\217\212\346\265\213\350\257\225/Template.cpp" deleted file mode 100644 index d351ba1..0000000 --- "a/\345\244\264\346\226\207\344\273\266\345\217\212\346\265\213\350\257\225/Template.cpp" +++ /dev/null @@ -1,178 +0,0 @@ -#pragma comment(linker, "/stack:200000000") -#pragma GCC optimize("Ofast") -//#pragma GCC optimize(3) -//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native") -//#pragma GCC target("sse3","sse2","sse") -//#pragma GCC target("avx","sse4","sse4.1","sse4.2","ssse3") -//#pragma GCC target("f16c") -//#pragma GCC optimize("inline","fast-math","unroll-loops","no-stack-protector") -//#pragma GCC diagnostic error "-fwhole-program" -//#pragma GCC diagnostic error "-fcse-skip-blocks" -//#pragma GCC diagnostic error "-funsafe-loop-optimizations" -//#pragma GCC diagnostic error "-std=c++14" -#include "bits/stdc++.h" -#include "ext/pb_ds/tree_policy.hpp" -#include "ext/pb_ds/assoc_container.hpp" - -#define PB push_back -#define PF push_front -#define LB lower_bound -#define UB upper_bound -#define fr(x) freopen(x,"r",stdin) -#define fw(x) freopen(x,"w",stdout) -#define REP(x, l, u) for(ll x = l;x=u;x--) -#define complete_unique(a) a.erase(unique(begin(a),end(a)),end(a)) -#define mst(x, a) memset(x,a,sizeof(x)) -#define all(a) begin(a),end(a) -#define rall(a) rbegin(a),rend(a) -#define PII pair -#define PLL pair -#define MP make_pair -#define lowbit(x) ((x)&(-(x))) -#define bitcnt(x) (__builtin_popcountll(x)) -#define lson (ind<<1) -#define rson (ind<<1|1) -#define se second -#define fi first -#define sz(x) ((int)x.size()) -#define EX0 exit(0); - -typedef long long ll; -typedef unsigned long long ull; -typedef double db; -typedef long double ld; -using namespace __gnu_pbds; //required -using namespace std; -template using ordered_set = tree, rb_tree_tag, tree_order_statistics_node_update>; -typedef vector VLL; -typedef vector VI; -const ll mod = 1e9 + 7; - - -string to_string (string s) { return '"' + s + '"'; } - -string to_string (const char *s) { return to_string ((string) s); } - -string to_string (bool b) { return (b ? "true" : "false"); } - -template -string to_string (pair p) { return "(" + to_string (p.first) + ", " + to_string (p.second) + ")"; } - -template -string to_string (A v) { - bool first = true; - string res = "{"; - for (const auto &x : v) { - if (!first) { res += ", "; } - first = false; - res += to_string (x); - } - res += "}"; - return res; -} - -void debug_out () { cerr< -void debug_out (Head H, Tail... T) { - cerr<<" "< -inline bool upmin (T &a, const S &b) { return a > b ? a = b, 1 : 0; } - -template -inline bool upmax (T &a, const S &b) { return a < b ? a = b, 1 : 0; } - - -ull twop (ll x) { return 1ULL< -T sqr (T x) { return x * x; } - -ll gcd (ll a, ll b) { - a = abs (a), b = abs (b); - while (b != 0) { - a %= b; - swap (a, b); - } - return a; -} - -ll fast (ll a, ll b, ll mod) { - a %= mod; - if (b < 0)a = inverse (a, mod), b = -b; - ll ans = 1; - while (b) { - if (b & 1)ans = ans * a % mod; - a = a * a % mod; - b /= 2; - } - return ans % mod; -} - - -namespace SOLVE { - void main () { - - } -} - - -signed main () { -#ifdef LOCAL - fr("/Users/zhangqingchuan/Desktop/cp/cp/input.txt"); - fw("/Users/zhangqingchuan/Desktop/cp/cp/output.txt"); -#endif - ios::sync_with_stdio (false); - cin.tie (nullptr); - cout.tie (nullptr); - - - int t = 1; -// cin >> t; - for (int i = 1; i <= t; i++) { -// cout<<"Case #"< exkmp(const string &s) { - int n = s.size(); - vector z(n); - int x = 0, y = 0; - for(int i = 1; i < n; i++) { - z[i] = max(0, min(z[i - x], y - i + 1)); - while(i + z[i] < n && s[z[i]] == s[i + z[i]]) { - x = i; - y = i + z[i]; - z[i]++; - } - } - z[0] = n; - return z; -} diff --git "a/\345\255\227\347\254\246\344\270\262/String-Hash.cpp" "b/\345\255\227\347\254\246\344\270\262/String-Hash.cpp" deleted file mode 100644 index 214cd67..0000000 --- "a/\345\255\227\347\254\246\344\270\262/String-Hash.cpp" +++ /dev/null @@ -1,67 +0,0 @@ -// 1-based -// 支持char/int/ll -// push - 加在末尾 -// build - 重建 -// hash(l,r) - 获取 [l,r] 的 hash -struct Hashing { - array seed, mod; - array, 2> hs, pw; - - Hashing(array seed = {28, 31}, - array mod = {1000000007, 1000173169}) : seed(seed), mod(mod) { - init(); - } - - void init() { - hs[0] = hs[1] = {0}; - pw[0] = pw[1] = {1}; - } - - void push(ll ch) { - assert(ch != 0); - for(int i = 0; i < 2; i++) { - pw[i].push_back(pw[i].back() * seed[i] % mod[i]); - hs[i].push_back((hs[i].back() * seed[i] + ch) % mod[i]); - } - } - - void pop() { - assert(size() > 1); - for(int i = 0; i < 2; i++) { - pw[i].pop_back(); - hs[i].pop_back(); - } - } - - - template - void build(T begin, T end) { - init(); - while(begin != end) { - push(*(begin++)); - } - } - - template - void push(T begin, T end) { - while(begin != end) { - push(*(begin++)); - } - } - - array hash(int l, int r) { - l--; - assert(l <= r and r <= size()); - array ans{0, 0}; - if(l >= r)return ans; - for(int i = 0; i < 2; i++) { - ans[i] = (hs[i][r] - hs[i][l] * pw[i][r - l]) % mod[i]; - if(ans[i] < 0)ans[i] += mod[i]; - } - return ans; - } - - int size() { - return hs[0].size() - 1; - } -}; diff --git "a/\345\255\227\347\254\246\344\270\262/Suffix-Array.cpp" "b/\345\255\227\347\254\246\344\270\262/Suffix-Array.cpp" deleted file mode 100644 index cd74ccc..0000000 --- "a/\345\255\227\347\254\246\344\270\262/Suffix-Array.cpp" +++ /dev/null @@ -1,92 +0,0 @@ -template -class SuffixArray { -public: - void build_SA(const T &str, vector &sa, vector &rk) { - - const int len = sz(str); - vector > ord[2] = {vector < pair < PII, int >> (len), vector < pair < PII, int >> (len)}; - sa = std::vector(len); - rk = std::vector(len); - REP(i, 0, len) - { - ord[1][i] = MP(MP(str[i], 0), i); - } - for (int b = 0;; b++) { - int cur = b % 2; - sort(all(ord[cur ^ 1])); - REP(i, 0, len) - { - rk[ord[cur ^ 1][i].se] = - i == 0 ? 0 : (rk[ord[cur ^ 1][i - 1].se] + (ord[cur ^ 1][i - 1].fi != ord[cur ^ 1][i].fi)); - } - if (rk[ord[cur ^ 1][len - 1].se] == len - 1)break; - REP(i, 0, len) - ord[cur][i] = MP(MP(rk[i], (i + twop(b) < len) ? rk[i + twop(b)] : -inf), i); - } - REP(i, 0, len) - sa[rk[i]] = i; - } - - vector > st; - - void build_height(const T &str, const vector &sa, const vector &rk, vector &height) { - height = std::vector(sz(str), 0); - const int len = sz(str); - REP(i, 0, len) - { - if (rk[i] == 0)continue; - while (i + height[rk[i]] < len && sa[rk[i] - 1] + height[rk[i]] < len && - str[i + height[rk[i]]] == str[sa[rk[i] - 1] + height[rk[i]]]) { - height[rk[i]]++; - } - if (i != len - 1) { - height[rk[i + 1]] = max(0, height[rk[i]] - 1); - } - } - } - - T str; - vector sa, rk; - - void init(const T &s, bool getHeight = 0) { - str = s; - build_SA(str, sa, rk); - if (getHeight) { - st = vector < vector < int >> (ceil(log2(sz(s)) + eps), vector(sz(s))); - build_height(str, sa, rk, st[0]); - REP(i, 0, sz(st) - 1) - { - REP(j, 0, sz(s) - twop(i)) - { - st[i + 1][j] = min(st[i][j], st[i][j + twop(i)]); - } - } - } - } - - void test() { - REP(i, 0, sz(str)) - { - cout << (i) << " "; - REP(j, sa[i], sz(str)) - { - if (str[j] < 0)break; - cout << char(str[j]); - } - cout << endl; - } - } - - int getLCP(int l, int r) { - if (l == r) { - return sz(str) - l; - } else { - l = rk[l], r = rk[r]; - if (l > r)swap(l, r); - l++; - int lvl = floor(log2(r - l + 1) + eps); - return min(st[lvl][l], st[lvl][r - twop(lvl) + 1]); - } - } - -}; diff --git "a/\346\225\260\345\255\246/Gaussian-Elimination.cpp" "b/\346\225\260\345\255\246/Gaussian-Elimination.cpp" deleted file mode 100644 index 8a72b16..0000000 --- "a/\346\225\260\345\255\246/Gaussian-Elimination.cpp" +++ /dev/null @@ -1,48 +0,0 @@ -typedef double flt; -const int MAXN = 64; -const flt eps = 1e-8; - -bool gauss(flt a[][MAXN], flt b[], int n) { - for (int k = 0, i, j, s; k < n; ++k) { - for (s = k, i = k + 1; i < n; ++i) - if (fabs(a[i][k]) > fabs(a[s][k]))s = i; - if (fabs(a[s][k]) < eps)return false; - if (s != k) { - std::swap(b[s], b[k]); - for (i = k; i < n; ++i) std::swap(a[s][i], a[k][i]); - } - for (j = k + 1; j < n; ++j) { - flt t = -a[j][k] / a[k][k]; - b[j] += b[k] * t; - for (i = k + 1; i < n; ++i)a[j][i] += t * a[k][i]; - } - } - for (int i = n - 1; i >= 0; --i) { - b[i] /= a[i][i]; - for (int j = 0; j < i; ++j)b[j] -= a[j][i] * b[i]; - } - return 1; -} - -int det_mod(int n, int mod, vector > mat) { - for (int i = 0; i < n; ++i) { - for (int j = 0; j < n; ++j) { - mat[i][j] %= mod; - } - } - ll ret = 1; - for (int i = 0; i < n; ++i) { - for (int j = i + 1; j < n; ++j) - for (; mat[j][i]; ret = -ret) { - ll t = mat[i][i] / mat[j][i]; - for (int k = i; k < n; ++k) { - mat[i][k] = (mat[i][k] - mat[j][k] * t) % mod; - std::swap(mat[j][k], mat[i][k]); - } - } - if (mat[i][i] == 0) return 0; - ret = ret * mat[i][i] % mod; - } - if (ret < 0) ret += mod; - return (int) ret; -} diff --git "a/\346\225\260\345\255\246/Polynomial.cpp" "b/\346\225\260\345\255\246/Polynomial.cpp" deleted file mode 100644 index 7552138..0000000 --- "a/\346\225\260\345\255\246/Polynomial.cpp" +++ /dev/null @@ -1,96 +0,0 @@ -using fft::N; - - -// call init before use -namespace Poly { - int tmp1[N], tmp2[N], tmp3[N], mod = 998244353; - int iv[N]; - - void init () { - iv[1] = 1; - for (int i = 2; i < N; ++i) { - iv[i] = (mod - (ll) mod / i * iv[mod % i] % mod); - } - } - - void prepare (int poly[], int n) { - for (int i = 0; i < n; i++)poly[i] = MOD (poly[i], mod); - } - - // res = 1 / poly - void inv (int poly[], int res[], int n) { - prepare (poly, n); - int deg = n - 1; - std::vector degs; - while (deg > 0) { - degs.push_back (deg); - deg >>= 1; - } - std::reverse (degs.begin (), degs.end ()); - res[0] = inverse (poly[0], mod); - deg = 1; - for (int t: degs) { - fft::conv (poly, res, t + 1, deg, mod, tmp1); - fft::conv (res, tmp1 + deg, t + 1 - deg, t + 1 - deg, mod, tmp1); - for (int i = 0; i < t + 1 - deg; ++i) { - res[i + deg] = mod - tmp1[i]; - } - deg = t + 1; - } - } - - // res = ln(poly), poly[0] should be 1 - void log (int poly[], int res[], int n) { - prepare (poly, n); - assert(poly[0] == 1); - inv (poly, tmp2, n); - for (int i = 0; i < n - 1; ++i) { - res[i] = (ll) poly[i + 1] * (i + 1) % mod; - } - fft::conv (res, tmp2, n - 1, n, mod, res); - for (int i = n - 1; i >= 1; --i) { - res[i] = (ll) res[i - 1] * iv[i] % mod; - } - res[0] = 0; - } - - // res = exp(poly), poly[0] should be 0 - void exp (int poly[], int res[], int n) { - prepare (poly, n); - assert(poly[0] == 0); - while (n & n - 1)n += lowbit(n); - if (n == 1) { - res[0] = 1; - return; - } - exp (poly, res, n>>1); - log (res, tmp3, n); - for (int i = 0; i < n; ++i) { - tmp3[i] = poly[i] - tmp3[i]; - if (tmp3[i] < 0) tmp3[i] += mod; - } - if (++tmp3[0] == mod) tmp3[0] = 0; - fft::conv (tmp3, res, n, n, mod, res); - memset (res + n, 0, sizeof (*res) * n); - } - - // res = sqrt(poly), poly[0] should be 1 - void sqrt (int poly[], int res[], int n) { - prepare (poly, n); - assert(poly[0] == 1); - while (n & (n - 1)) n += n & (-n); - if (n == 1) { - res[0] = 1; - return; - } - sqrt (poly, res, n>>1); - fill (tmp2 + n / 2, tmp2 + n, 0); - fill (res + n / 2, res + n, 0); - inv (res, tmp2, n); - - fft::conv (poly, tmp2, n, n, mod, tmp1); - for (int i = 0; i < n; i++) { - res[i] = (ll) iv[2] * ((res[i] + tmp1[i]) % mod) % mod; - } - } -}