├── ACM-OI 's Strategy.md ├── ACM-Tech.txt ├── Basic ├── BFS │ ├── BFS │ ├── BFS.cpp │ └── BFS.py ├── BackTracking │ ├── Hamilton path.cpp │ ├── Knight_tour.cpp │ ├── Nqueue.cpp │ └── Sudoku.cpp ├── BinarySearchTree │ ├── BST_Count&height&diameter.cpp │ ├── BST_Normal_Operation.cpp │ ├── BST_traverse.cpp │ └── Banlancing of BST.cpp ├── ConvexHullTrick.cpp └── DFS │ ├── dfs │ ├── dfs.cpp │ └── dfs.py ├── Black_magic ├── &与%效率.txt ├── O(1)快速乘.cpp ├── bitset.h ├── fastIO.cpp ├── pb_ds(笔记).txt ├── rope.txt ├── 二进制数中1的个数.cpp └── 扩栈.cpp ├── Class ├── BigInt.cpp ├── Frac.cpp └── 对拍.cpp ├── DataStructure ├── 01Tire求区间异或和的最大值.cpp ├── CDQ分治.cpp ├── Cartesian_Tree.cpp ├── Circle-Square-Tree Maximum independent set.cpp ├── DLX.cpp ├── HASH.cpp ├── KMP.cpp ├── LCA.cpp ├── LCT.cpp ├── Splay_Tree - v1.cpp ├── Splay_Tree - v2.cpp └── merge_sort.cpp ├── Geometry ├── Geometry2d (Basic).h ├── Geometry3d (Basic).h └── polygon.cpp ├── Graph-theory ├── Connectivity │ ├── BCC (multi-version).cpp │ ├── BCC_edge(1).cpp │ ├── BCC_edge(2).cpp │ ├── BCC_vertex(1).cpp │ ├── BCC_vertex(2).cpp │ ├── Kosaraju.cpp │ └── Tarjan_SCC.cpp ├── Flows and cuts │ ├── Dinic(1).cpp │ ├── Dinic(2).cpp │ ├── Edmonds–Karp.cpp │ ├── Ford-Fulkerson.cpp │ ├── MinCostMaxFlow.cpp │ ├── edge-disjoint-path(1).cpp │ ├── edge-disjoint-path(2).cpp │ └── maximum_flow_goldberg_tarjan.cpp ├── Matching │ ├── Kuhn-Munkras (KM).cpp │ ├── 匈牙利算法 O(n^3).cpp │ └── 匈牙利算法 O(nm).cpp ├── Shortest-path │ ├── Bellman-Ford.cpp │ ├── Dijkstra(1).cpp │ ├── Dijkstra(2).cpp │ ├── Dijkstra(求最短路和次短路以及其路径数).cpp │ ├── Floyd–Warshall.cpp │ ├── K短路.cpp │ ├── SPFA(1).cpp │ └── SPFA(2).cpp └── Spanning-tree │ ├── Kruskal (MST和次小生成树).cpp │ ├── prim.cpp │ └── 曼哈顿距离MST.cpp ├── Mathematics ├── BSGS.cpp ├── Berlekamp-Massey.cpp ├── Berlekamp-Massey(Complete).cpp ├── CRT(模数不互质).cpp ├── CRT(模数互质).cpp ├── Cantor.cpp ├── Check_primitive_root.cpp ├── Determinant.cpp ├── Dirichlet卷积.cpp ├── EX_BSGS.cpp ├── Euler_Function.cpp ├── Extends_GCD.cpp ├── FFT+CDQ.cpp ├── FFT大整数乘法.cpp ├── Fib数模n的循环节.cpp ├── Guass.cpp ├── MTT.cpp ├── Meissel-Lehmer.cpp ├── [1,n]与a互素个数.cpp ├── bernoulli_number.cpp ├── factorial.cpp ├── gauss_elimination.cpp ├── the-meissel-lehmer-lagarias-miller-odlyzko-method.cpp ├── 任意模数FFT+多项式取逆.cpp ├── 康拓展开和逆康拓展开.cpp ├── 快速乘.cpp ├── 快速幂.cpp ├── 杜教筛.cpp ├── 类欧几里得.cpp └── 线性筛prime+phi+mu.cpp ├── Others └── README.md ├── README.md ├── Skill Trees.txt └── String ├── AC自动机.cpp ├── AhoCorasick.cpp ├── EX_KMP.cpp ├── KMP(含注释).cpp ├── KMP.cpp ├── LIS.cpp ├── Manacher.cpp ├── SA.cpp ├── manacher (2).cpp ├── multi - String Hash.cpp ├── suffix array.cpp ├── 动态Trie.cpp ├── 回文树.cpp └── 静态Trie.cpp /ACM-OI 's Strategy.md: -------------------------------------------------------------------------------- 1 | 1. 算法 (AG) 2 | 1. 动态规划 (DP) 3 | 1. DAG 模型 4 | 1. 背包DP 5 | 1. 数位DP 6 | 1. 插头DP 7 | 1. 子树DP 8 | 1. 区间DP 9 | 1. 决策优化 10 | 1. 分步式转移 11 | 1. 单调性分治 12 | 1. 维护移动端点 13 | 1. 斜率优化 14 | 1. 四边形不等式 15 | 1. 网络流 (NF) 16 | 1. 网络流线性规划 17 | 1. 上下界网络流 18 | 1. 最小割 19 | 1. 费用流 20 | 1. Edmond-Karp (EK) 21 | 1. Capacity Scaling 22 | 1. Dinic&SAP 23 | 1. HLPP 24 | 1. 差分约束 (DC) 25 | 1. 通用线性规划 (LP) 26 | 1. 单纯形算法 27 | 1. 分数规划 (FP) 28 | 1. 贪心 (GE) 29 | 1. 分治 (DAC) 30 | 1. 序列分治 31 | 1. CDQ&整体二分&线段树分治 32 | 1. 快速排序 33 | 1. 快速选择 34 | 1. Median of Medians 35 | 1. 树分治 36 | 1. 点/边分治 37 | 1. 重链剖分 38 | 1. 树上启发式合并 39 | 1. 长链剖分 40 | 1. 搜索 (SR) 41 | 1. DFS (DFS) 42 | 1. BFS (BFS) 43 | 1. 搜索优化与剪枝 44 | 1. A* (AS) 45 | 1. 迭代加深搜索 (ID) 46 | 1. 折半搜索 (MIM) 47 | 1. 随机化及近似 (RAN) 48 | 1. 爬山 49 | 1. 模拟退火 50 | 1. 遗传算法 51 | 1. 机器学习基础 52 | 1. 离线逆序 53 | 1. 莫队算法 54 | 1. 散列 (HS) 55 | 1. 数据结构 (DS) 56 | 1. 栈 (STK) 57 | 1. 队列 (QUE) 58 | 1. 散列表 (HST) 59 | 1. 堆 (HP) 60 | 1. 二叉堆 61 | 1. 可并堆 62 | 1. 二叉查找树 (BST) 63 | 1. 堆树 (THP) 64 | 1. 伸展树 (SPT) 65 | 1. 红黑树 (RBT) 66 | 1. 替罪羊树 (SGT) 67 | 1. 树状数组 (BIT) 68 | 1. 线段树 (SGM) 69 | 1. 划分树与归并树 70 | 1. 并查集 (UFS) 71 | 1. 带权并查集 72 | 1. 路径压缩 73 | 1. 按秩合并 74 | 1. Sparse Table (ST) 75 | 1. K维树 (KDT) 76 | 1. 动态树 77 | 1. 点/边分治树 (DCT) 78 | 1. Link-Cut Tree (LCT) 79 | 1. 欧拉回路树 (ETT) 80 | 1. AAA Tree & Top Tree 81 | 1. 动态图 82 | 1. 图论 (GT) 83 | 1. 最小生成树 84 | 1. Prim 算法 (PM) 85 | 1. Kruskal 算法 (KS) 86 | 1. Boruvka 算法 87 | 1. 最小树形图 88 | 1. 朱-刘算法 89 | 1. 斯坦纳树 90 | 1. 最短路径 91 | 1. dijkstra 算法 (DJ) 92 | 1. Bellman-Ford 算法 (BFD) 93 | 1. Johnson 算法 94 | 1. Floyd 算法 (FL) 95 | 1. 欧拉路&哈密顿路 96 | 1. 连通性 97 | 1. 点/边双连通分量 (BCC) 98 | 1. 强连通性 (SCC) 99 | 1. 支配树 100 | 1. 匹配、划分与覆盖 101 | 1. KM 算法 (KM) 102 | 1. 交错树 103 | 1. 带花树算法 (BL) 104 | 1. Tutte 矩阵与一般图匹配 105 | 1. 覆盖集与独立集 106 | 1. 稳定婚姻问题与 GS 算法 (GS) 107 | 1. Hall 定理 108 | 1. DAG 路径覆盖 109 | 1. Dilworth 定理 110 | 1. 2-SAT 111 | 1. 虚树 112 | 1. 仙人掌 113 | 1. 圆方树 114 | 1. 弦图与区间图 115 | 1. 图的树分解 116 | 1. 最小割 117 | 1. 最小割树 118 | 1. Stoer-Wagner 算法 119 | 1. 平面图 120 | 1. 平面图对偶图 121 | 1. 网格图 122 | 1. 计算几何 (CG) 123 | 1. 几何向量 124 | 1. 二维凸包 125 | 1. 凸包算法 126 | 1. 卷包裹法 127 | 1. 动态凸包 128 | 1. 三维凸包 129 | 1. 半平面交 130 | 1. 旋转卡壳 131 | 1. 三角剖分 132 | 1. V图 133 | 1. 路径规划 134 | 1. 代数 (AB) 135 | 1. 微积分基础 136 | 1. Simpson 积分算法 137 | 1. 线性代数 138 | 1. 矩阵基础 139 | 1. 高斯消元 140 | 1. 拟阵 141 | 1. Matrix-Tree 定理 142 | 1. 线性递推 143 | 1. 多项式与幂级数 144 | 1. DFT/FFT (FT) 145 | 1. NTT 146 | 1. Bluestein 算法 147 | 1. 多项式基本运算 148 | 1. 多项式除法 149 | 1. 多项式基本初等函数 150 | 1. FWT (FWT) 151 | 1. 子集变换 152 | 1. 抽象代数 153 | 1. 置换群 154 | 1. Schreier-Sims 算法 155 | 1. 数论 (NT) 156 | 1. 同余和整除 157 | 1. 欧几里得算法 158 | 1. 扩展欧几里得算法 159 | 1. 类欧几里得算法 160 | 1. 欧拉定理 161 | 1. 二次剩余 162 | 1. 原根及离散对数 163 | 1. BSGS 164 | 1. lucas 定理 165 | 1. 质数与简单数论函数 166 | 1. 埃氏筛 167 | 1. 欧拉筛 168 | 1. 莫比乌斯反演 169 | 1. 数论函数快速求和 170 | 1. 杜教筛 171 | 1. 洲阁筛 172 | 1. 素性测试 173 | 1. Miller-Robin (MR) 174 | 1. Pollard's Rho 因子分解 175 | 1. 组合计数 (CE) 176 | 1. 计数原理 177 | 1. 容斥原理 178 | 1. 计数数列 179 | 1. 斯特林数 180 | 1. 卡特兰数 181 | 1. 伯努利数 182 | 1. 生成函数 (GF) 183 | 1. 杨氏矩阵 184 | 1. Burnside 引理 185 | 1. Polya 定理 186 | 1. 博弈论与信息论 (GI) 187 | 1. 博弈基础 188 | 1. 组合游戏 189 | 1. 博弈树与 DAG 模型 190 | 1. Sprague-Grundy 函数 (SG) 191 | 1. Nim (NIM) 192 | 1. Nim 积 193 | 1. 威佐夫博弈 194 | 1. 不平等博弈 195 | 1. 超现实数 196 | 1. 不完全信息博弈 197 | 1. 通信与数据压缩 198 | 1. 校验码 199 | 1. 哈夫曼编码 200 | 1. 游程编码 201 | 1. 形式语言,自动机与串处理 (FAS) 202 | 1. 串处理 (STR) 203 | 1. 模式匹配 204 | 1. KMP 算法 (KMP) 205 | 1. AC 自动机 206 | 1. Shift-And 算法 207 | 1. 字典树 (TRI) 208 | 1. 后缀树 209 | 1. 后缀数组 (SA) 210 | 1. 后缀自动机 (SAM) 211 | 1. Border 212 | 1. Periodicity 引理 213 | 1. 回文串 214 | 1. manacher 算法 215 | 1. 回文自动机 (PAM) 216 | 1. 形式语言 217 | 1. 正则表达式 (RE) 218 | 1. 有限状态自动机 (DFA) 219 | 1. 并行计算 220 | -------------------------------------------------------------------------------- /ACM-Tech.txt: -------------------------------------------------------------------------------- 1 | [ ] 基础算法: 2 | [x] 模拟 3 | [x] 枚举 4 | [x] 贪心 5 | [x] 高精度 6 | [x] 排序 7 | [x] 递推 8 | [x] 递归 9 | [x] 二分 10 | [ ] 01分数规划 11 | [ ] 整体二分 12 | [x] 倍增 13 | [x] 位运算 14 | [x] 离散化 15 | [ ] 分块 16 | [x] 前缀和 17 | [x] 启发式合并 18 | [x] 分治 19 | [ ] 随机化 20 | [x] 莫队算法 21 | 22 | [ ] 数据结构 23 | [x] 队列 24 | [x] 栈 25 | [x] 堆 26 | [x] 链表 27 | [x] 哈希表 28 | [x] 树状数组 29 | [x] 线段树 30 | [ ] 平衡树 31 | [ ] Spaly 32 | [ ] Treap 33 | [ ] SBT 34 | [x] 主席树 35 | [ ] KD树 36 | [ ] 树套树 37 | [x] STL 38 | 39 | [ ] 图论 40 | [ ] 搜索 41 | [x] DFS 42 | [x] BFS 43 | [x] 记忆化 44 | [ ] A* 45 | [ ] IDA* 46 | [ ] 模拟退火 47 | [ ] 爬山算法 48 | [ ] 蚁群算法? 49 | [x] 并查集 50 | [x] 欧拉图 51 | [x] 拓扑排序 52 | [ ] 最短路 53 | [x] SPFA 54 | [x] Dijkstra 55 | [x] Floyd 56 | [ ] k短路 57 | [x] 差分约束 58 | [x] Tarjan 59 | [x] 强连通 60 | [x] 双连通 61 | [x] LCA 62 | [x] 2-SAT 63 | [ ] 二分图 64 | [ ] 最大匹配 65 | [ ] 最大权匹配 66 | [ ] 网络流 67 | [ ] 最大流最小割 68 | [ ] 费用流 69 | [ ] 有界流 70 | [ ] 树 71 | [x] 最小生成树 72 | [x] DFS序 73 | [x] 重心 74 | [x] 直径 75 | [x] LCA 76 | [x] 树分治 77 | [ ] 树同构 78 | [ ] 树链剖分 79 | [ ] LCT 80 | [ ] 基环树 81 | [ ] 带花树(非二分图最大匹配) 82 | [x] 最小树形图 83 | 84 | [ ] 字符串 85 | [x] KMP 86 | [x] 最小表示法 87 | [x] AC自动机 88 | [x] Trie树 89 | [x] 后缀数组 90 | [x] 后缀自动机 91 | [x] Manacher 92 | [x] 回文自动机 93 | 94 | [ ] DP 95 | [x] 背包 96 | [x] 区间DP 97 | [x] 树形DP 98 | [x] 数位DP 99 | [x] 期望DP 100 | [x] 记忆化搜索DP 101 | [x] 状压DP 102 | [ ] 轮廓线DP 103 | [x] 四边形不等式优化 104 | [x] 斜率优化 105 | 106 | [ ] 几何 107 | [x] 叉积和点积 108 | [x] 凸包 109 | [x] 旋转卡壳 110 | [x] 半平面交 111 | [x] Pick定理 112 | [x] 辛普森积分 113 | [x] 三角剖分 114 | [ ] 随机增量 115 | [ ] 反演变换 116 | 117 | [ ] 数学 118 | [ ] 博弈 119 | [x] SG函数 120 | [ ] A-Beta剪枝 121 | [ ] 极大极小搜索 122 | [x] 线性筛 123 | [x] 素数测试 124 | [x] 欧拉函数 125 | [x] 快速幂 126 | [x] GCD 127 | [x] EXGCD 128 | [x] 乘法逆元 129 | [x] CRT 130 | [x] 容斥 131 | [x] 矩阵 132 | [x] Poyla定理 133 | [x] 组合数 134 | [ ] BSGS 135 | [ ] 单纯形 136 | [x] 拉格朗日插值法 137 | [x] FFT & NTT 138 | [x] 多项式求逆&开方 139 | [x] 反演 140 | -------------------------------------------------------------------------------- /Basic/BFS/BFS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzyrapx/Algorithmic_Template/6000f22159c74773ee3a9be329b17f7cf278494b/Basic/BFS/BFS -------------------------------------------------------------------------------- /Basic/BFS/BFS.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | using namespace std; 4 | 5 | class Gragh { 6 | public: 7 | Gragh(int num_nodes):adj_list(num_nodes),dist(num_nodes,-1){} 8 | 9 | void add_edge(int start, int end); 10 | vector>adj_list; 11 | vectordist; 12 | }; 13 | void bfs(Gragh &g, int source); 14 | void print(const Gragh& g); 15 | /* 16 | Input format: 17 | node_num edg_num source 18 | u -> v 19 | u -> v 20 | */ 21 | void bfs(Gragh &g, int source){ 22 | vectorvis(g.adj_list.size(),false); 23 | queueque; 24 | que.push(source); 25 | vis[source] = true; 26 | g.dist[source] = 0; 27 | while(!que.empty()) { 28 | int cur_node = que.front(); 29 | vectorcur_node_adj = g.adj_list[cur_node]; 30 | for(int i = 0; i < (int)cur_node_adj.size(); i++) { 31 | int adj_node = cur_node_adj[i]; 32 | if(vis[adj_node] == true) continue; 33 | vis[adj_node] = true; 34 | g.dist[adj_node] = g.dist[cur_node] + 1; 35 | que.push(adj_node); 36 | } 37 | que.pop(); 38 | } 39 | } 40 | void print(const Gragh &g) { 41 | std::cout << "node ids" << " "; 42 | for(int i = 0; i < (int)g.adj_list.size(); i++) { 43 | std::cout << " " << i; 44 | } 45 | std::cout << '\n'; 46 | for(auto dis : g.dist) { 47 | std::cout << dis<< " "; 48 | } 49 | std::cout << '\n'; 50 | } 51 | 52 | void Gragh::add_edge(int start, int end) { 53 | adj_list[start].push_back(end); 54 | } 55 | 56 | int main(int argc, char const *argv[]) { 57 | int node_num, edge_node; 58 | int source; 59 | std::cin >> node_num >> edge_node >> source; 60 | 61 | Gragh g(node_num); 62 | // node's id start at zero 63 | for(int i = 0; i < edge_node; i++) { 64 | int u, v; 65 | std::cin >> u >> v; 66 | g.add_edge(u, v); 67 | } 68 | // std::cout << "input done !" << '\n'; 69 | // calc the distance from source to other node 70 | bfs(g, source); 71 | std::cout << "source: " << source << '\n'; 72 | print(g); 73 | return 0; 74 | } 75 | 76 | -------------------------------------------------------------------------------- /Basic/BFS/BFS.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | 3 | __author__ = "LzyRapx" 4 | 5 | from collections import defaultdict 6 | 7 | 8 | class Graph(): 9 | def __init__(self, number_of_node): 10 | self.graph = defaultdict(list) 11 | self.visited = [False] * number_of_node 12 | 13 | def addEdge(self, u, v): 14 | self.graph[u].append(v) 15 | 16 | def BFS(self, node): 17 | que = [] 18 | que.append(node) 19 | self.visited[node] = True 20 | 21 | while que: 22 | currentNode = que.pop(0) 23 | print(currentNode) 24 | 25 | children = self.graph[currentNode] 26 | for i in range(len(children)): 27 | if not self.visited[children[i]]: 28 | que.append(children[i]) 29 | self.visited[children[i]] = True 30 | 31 | if __name__ == "__main__": 32 | graph = Graph(3) # size of graph 33 | 34 | # add edge no limitation 35 | graph.addEdge(0,1) 36 | graph.addEdge(1,2) 37 | graph.addEdge(0,2) 38 | 39 | 40 | print("BFS starting from vertex zero : ") 41 | graph.BFS(0) 42 | -------------------------------------------------------------------------------- /Basic/BackTracking/Hamilton path.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | /* C/C++ program for solution of Hamiltonian Cycle problem using backtracking */ 8 | /* 9 | Hamiltonian Path in an undirected graph is a path that visits each vertex exactly once. 10 | A Hamiltonian cycle (or Hamiltonian circuit) is a Hamiltonian Path such that there is an 11 | edge (in graph) from the last vertex to the first vertex of the Hamiltonian Path 12 | */ 13 | 14 | #define V 5 // num of vertices 15 | 16 | int path[V]; 17 | bool isSafe(int v, bool graph[V][V], int path[], int pos) { 18 | if(graph[path[pos - 1]][v] == 0) return false; 19 | for(int i = 0; i < pos; i++) { 20 | if(path[i] == v) { // already visited 21 | return false; 22 | } 23 | } 24 | return true; 25 | } 26 | bool dfs(bool graph[V][V], int path[], int pos) { 27 | if(pos == V) { 28 | if(graph[path[V - 1]][path[0]] == 1) { 29 | return true; 30 | } 31 | else { 32 | return false; 33 | } 34 | } 35 | for(int v = 1; v < V; v++) { 36 | if(isSafe(v, graph, path, pos)) { 37 | path[pos] = v; 38 | if(dfs(graph, path, pos + 1) == true) { 39 | return true; 40 | path[pos] = -1; 41 | } 42 | } 43 | } 44 | return false; 45 | } 46 | void printSolution(int path[]) { 47 | printf( 48 | "Solution Exists:" 49 | "Hamiltonian Cycle: \n"); 50 | for (int i = 0; i < V; i++) printf(" %d ", path[i]); 51 | printf(" %d\n", path[0]); 52 | } 53 | void hamitltonCycle(bool graph[V][V]) { 54 | for(int i = 0; i < V; i++) { 55 | path[i] = -1; // default no one is visited. 56 | } 57 | path[0] = 0; 58 | if(!dfs(graph, path, 1)) { 59 | std::cout << "No solutions" << '\n'; 60 | } 61 | printSolution(path); 62 | } 63 | 64 | int main(int argc, char const *argv[]) { 65 | bool graph1[V][V] = {{0, 1, 0, 1, 0}, 66 | {1, 0, 1, 1, 1}, 67 | {0, 1, 0, 0, 1}, 68 | {1, 1, 0, 0, 1}, 69 | {0, 1, 1, 1, 0}, 70 | }; 71 | /* 72 | Let us create the following graph 73 | (0)--(1)--(2) 74 | | / \ | 75 | | / \ | 76 | | / \ | 77 | (3)-------(4) 78 | */ 79 | hamitltonCycle(graph1); 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /Basic/BackTracking/Knight_tour.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | #define N 8 13 | 14 | typedef struct chess_moves { 15 | int x,y; 16 | }chess_moves; 17 | 18 | void printTour(int tour[N][N]) { 19 | for(int i = 0; i < N; i++) { 20 | for(int j = 0; j < N; j++) { 21 | std::cout << tour[i][j] << '\t'; 22 | } 23 | std::cout << '\n'; 24 | } 25 | } 26 | bool check(chess_moves next_move, int tour[N][N]) { 27 | int i = next_move.x; 28 | int j = next_move.y; 29 | if((i >= 0 && i < N) && (j >= 0 && j < N) && (tour[i][j] == 0)) { 30 | return true; 31 | } 32 | return false; 33 | } 34 | bool dfs(int tour[N][N], chess_moves dir[], chess_moves cur_move, int move_count) { 35 | chess_moves next_move; 36 | if(move_count == N * N - 1) { 37 | return true; 38 | } 39 | for(int i = 0; i < N; i++) { 40 | next_move.x = cur_move.x + dir[i].x; 41 | next_move.y = cur_move.y + dir[i].y; 42 | if(check(next_move, tour)) { 43 | tour[next_move.x][next_move.y] = move_count + 1; 44 | if(dfs(tour, dir, next_move, move_count+1) == true) { 45 | return true; 46 | } 47 | else { 48 | tour[next_move.x][next_move.y] = 0; 49 | } 50 | } 51 | } 52 | return false; 53 | } 54 | void kightTour() { 55 | int tour[N][N]; 56 | for(int i = 0; i < N; i++) { 57 | for(int j = 0; j < N; j++) { 58 | tour[i][j] = 0; 59 | } 60 | } 61 | chess_moves dir[8] = { 62 | {2,1},{1,2},{-1,2},{-2,1}, 63 | {-2,-1},{-1,-2},{1,-2},{2,-1} 64 | }; 65 | chess_moves cur_move = {0,0}; 66 | if(!dfs(tour, dir, cur_move, 0)) { 67 | std::cout << "No solutions" << '\n'; 68 | } 69 | else { 70 | std::cout << "exist a solutions" << '\n'; 71 | printTour(tour); 72 | } 73 | } 74 | int main(int argc, char const *argv[]) { 75 | kightTour(); 76 | std::cout << '\n'; 77 | return 0; 78 | } 79 | -------------------------------------------------------------------------------- /Basic/BackTracking/Nqueue.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | setrow_c,col_c,right_slant,left_slant; 11 | void printBoard(vector>&board) { 12 | static int k = 1; 13 | cout << "Board " << k++ << ":\n"; 14 | for (int i = 0; i < board.size(); i++) { 15 | for (int j = 0; j < board[i].size(); j++) { 16 | cout << board[i][j] << " "; 17 | } 18 | cout << endl; 19 | } 20 | cout << endl; 21 | } 22 | bool check(int row, int col) { 23 | if(row_c.find(row) != row_c.end()) return false; 24 | if(col_c.find(col) != col_c.end()) return false; 25 | if(left_slant.find(row - col) != left_slant.end()) return false; 26 | if(right_slant.find(row + col) != right_slant.end()) return false; 27 | return true; 28 | } 29 | void setBoard(vector>&board, int row, int col) { 30 | board[row][col] = 1; 31 | row_c.insert(row); 32 | col_c.insert(col); 33 | left_slant.insert(row - col); 34 | right_slant.insert(row + col); 35 | } 36 | void unsetBoard(vector>&board, int row, int col) { 37 | board[row][col] = 0; 38 | row_c.erase(row); 39 | col_c.erase(col); 40 | left_slant.erase(row - col); 41 | right_slant.erase(row + col); 42 | } 43 | 44 | void dfs(vector> &board, int row) { 45 | if(row == board.size()) { 46 | printBoard(board); 47 | return; 48 | } 49 | for(int i = 0; i < (int)board.size(); i++) { 50 | if(check(row, i)) { 51 | setBoard(board, row, i); 52 | dfs(board, row + 1); 53 | unsetBoard(board, row, i); 54 | } 55 | } 56 | } 57 | int main(int argc, char const *argv[]) { 58 | int n; 59 | // std::cin >> n; 60 | n = 8; 61 | vector>board = std::vector>(n, vector(n,0)); 62 | dfs(board,0); 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /Basic/BackTracking/Sudoku.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | typedef long long ll; 10 | const ll mod = 1e9 + 7; 11 | using namespace std; 12 | 13 | const int N = 9; 14 | 15 | bool check_row(int grid[N][N], int row, int num) { 16 | for(int col = 0; col < N; col ++) { 17 | if(grid[row][col] == num) return true; 18 | } 19 | return false; 20 | } 21 | bool check_col(int grid[N][N], int col, int num) { 22 | for(int row = 0; row < N; row ++) { 23 | if(grid[row][col] == num) return true; 24 | } 25 | return false; 26 | } 27 | bool check_square(int grid[N][N], int boxStartRow, int boxStartCol, int num) { 28 | for(int row = 0; row < 3; row++) { 29 | for(int col = 0; col < 3; col++) { 30 | if(grid[row + boxStartRow][col + boxStartCol] == num) return true; 31 | } 32 | } 33 | return false; 34 | } 35 | bool check(int grid[N][N], int row, int col, int num) { 36 | return !check_row(grid, row, num) && !check_col(grid,col,num) && 37 | !check_square(grid, row - row % 3, col - col % 3, num); 38 | } 39 | void printGrid(int grid[N][N]) { 40 | for(int row = 0; row < N; row ++) { 41 | for(int col = 0; col < N; col ++) { 42 | printf("%2d", grid[row][col]); 43 | } 44 | printf("\n"); 45 | } 46 | } 47 | bool FindUnassignedLocation(int grid[N][N], int& row, int& col) { 48 | for(row = 0; row < N; row ++) { 49 | for(col = 0; col < N; col ++) { 50 | if(grid[row][col] == 0) return true; 51 | } 52 | } 53 | return false; 54 | } 55 | bool dfs(int grid[N][N]) { 56 | int row, col; 57 | if(!FindUnassignedLocation(grid, row, col)) return true; 58 | for(int num = 1; num <= 9; num ++) { 59 | if(check(grid, row, col, num)) { 60 | grid[row][col] = num; 61 | if(dfs(grid)) return true; 62 | grid[row][col] = 0; 63 | } 64 | } 65 | return false; 66 | } 67 | int main(int argc, char const *argv[]) { 68 | int grid[N][N] = {{3, 0, 6, 5, 0, 8, 4, 0, 0}, 69 | {5, 2, 0, 0, 0, 0, 0, 0, 0}, 70 | {0, 8, 7, 0, 0, 0, 0, 3, 1}, 71 | {0, 0, 3, 0, 1, 0, 0, 8, 0}, 72 | {9, 0, 0, 8, 6, 3, 0, 0, 5}, 73 | {0, 5, 0, 0, 9, 0, 6, 0, 0}, 74 | {1, 3, 0, 0, 0, 0, 2, 5, 0}, 75 | {0, 0, 0, 0, 0, 0, 0, 7, 4}, 76 | {0, 0, 5, 2, 0, 6, 3, 0, 0}}; 77 | if(dfs(grid)) { 78 | printGrid(grid); 79 | } 80 | else { 81 | std::cout << "No solutions." << '\n'; 82 | } 83 | return 0; 84 | } 85 | -------------------------------------------------------------------------------- /Basic/BinarySearchTree/BST_Count&height&diameter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | typedef long long ll; 10 | const ll mod = 1e9 + 7; 11 | using namespace std; 12 | 13 | struct Node { 14 | int val; 15 | struct Node *left, *right; 16 | }; 17 | struct Node* insert(int n) { 18 | Node *tmp = new Node; 19 | tmp -> val = n; 20 | tmp -> left = nullptr; 21 | tmp -> right =nullptr; 22 | return tmp; 23 | } 24 | 25 | void inorder(Node* root) { 26 | if(root != nullptr) { 27 | inorder(root -> left); 28 | std::cout << root -> val << ' '; 29 | inorder(root -> right); 30 | } 31 | } 32 | void postorder(Node* root) { 33 | if(root != nullptr) { 34 | postorder(root -> right); 35 | postorder(root -> left); 36 | std::cout << root -> val << ' '; 37 | } 38 | } 39 | void preorder(Node* root) { 40 | if(root != nullptr) { 41 | std::cout << root -> val << ' '; 42 | preorder(root -> left); 43 | preorder(root -> right); 44 | } 45 | } 46 | Node* build(Node* root, int n) { 47 | if(root == nullptr) { 48 | return insert(n); 49 | } 50 | else if(root -> val > n) { 51 | root -> left = build(root -> left, n); 52 | } 53 | else { 54 | root -> right = build(root -> right, n); 55 | } 56 | return root; 57 | } 58 | bool find(Node* root, int key) { 59 | if(root -> val > key && root -> left == nullptr) { 60 | return 0; 61 | } 62 | if(root -> val < key && root -> right == nullptr) { 63 | return 0; 64 | } 65 | if(root -> val == key) { 66 | return 1; 67 | } 68 | else if(root -> val > key) { 69 | find(root -> left, key); 70 | } 71 | else if(root -> val < key) { 72 | find(root -> right, key); 73 | } 74 | else { 75 | return 0; 76 | } 77 | return 0; 78 | } 79 | int countNodes(Node* root) { 80 | if(root == nullptr) { 81 | return 0; 82 | } else { 83 | return 1 + countNodes(root -> left) + countNodes(root -> right); 84 | } 85 | } 86 | int height(Node* root) { 87 | if(root == nullptr) { 88 | return 0; 89 | } 90 | return 1 + max(height(root -> left), height(root -> right)); 91 | } 92 | int diameter(Node* root) { 93 | if(root == nullptr) { 94 | return 0; 95 | } 96 | return max(1 + height(root -> left) + height(root -> right), 97 | max(diameter(root -> left), diameter(root -> right))); 98 | } 99 | int main(int argc, char const *argv[]) { 100 | Node* root = nullptr; 101 | root = build(root ,5); 102 | // std::cout << root << '\n'; 103 | build(root, 10); 104 | build(root, 20); 105 | build(root, 21); 106 | build(root, 14); 107 | build(root, 9); 108 | build(root, 3); 109 | build(root, 12); 110 | build(root, 21); 111 | // Inorder permutate from left -> root -> right 112 | cout << "The Inorder traversal of the tree is : "; 113 | inorder(root); 114 | cout << endl; 115 | // Postorder permutate from left -> right -> root 116 | cout << "The Postorder traversal of the tree is : "; 117 | postorder(root); 118 | cout << endl; 119 | // Preorder permutate from root -> left -> right 120 | cout << "The Preorder traversal of the tree is : "; 121 | preorder(root); 122 | cout << endl; 123 | // Count total number of nodes in the tree 124 | cout << "The number of nodes in the tree : "; 125 | cout << countNodes(root) << endl; 126 | cout << "The height of the tree is : "; 127 | cout << height(root) << endl; 128 | cout << "The diameter of the tree is : "; 129 | cout << diameter(root) << endl; 130 | return 0; 131 | } 132 | -------------------------------------------------------------------------------- /Basic/BinarySearchTree/BST_Normal_Operation.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | typedef long long ll; 10 | using namespace std; 11 | 12 | struct Node { 13 | string data; 14 | Node *left; 15 | Node *right; 16 | }; 17 | Node* getNode(string data) { 18 | Node* tmp= new Node; 19 | tmp -> data = data; 20 | tmp -> left = nullptr; 21 | tmp -> right = nullptr; 22 | return tmp; 23 | } 24 | // level order 25 | void level_order(Node* root) { 26 | queueque; 27 | que.push(root); 28 | que.push(getNode("root")); 29 | while(!que.empty()) { 30 | Node* tmp = que.front(); 31 | que.pop(); 32 | if(!que.empty() && tmp -> data == "root") { 33 | std::cout << '\n'; 34 | que.push(tmp); 35 | } 36 | else if(tmp -> data != "root") { 37 | std::cout << tmp -> data << ' '; 38 | } 39 | if(tmp -> left) { 40 | que.push(tmp -> left); 41 | } 42 | if(tmp -> right) { 43 | que.push(tmp -> right); 44 | } 45 | } 46 | } 47 | Node* insert_node(Node* root, string data) { 48 | // std::cout << "r = " << root << '\n'; 49 | if(root == nullptr) { 50 | return getNode(data); 51 | } 52 | if(root -> data > data) { 53 | root -> left = insert_node(root -> left, data); 54 | } 55 | else { 56 | root -> right = insert_node(root -> right, data); 57 | } 58 | return root; 59 | } 60 | string find_help(Node* root, string k) { 61 | if(root == nullptr) { 62 | return "not exist"; 63 | } 64 | else if(root -> data > k) { 65 | return find_help(root -> left, k); 66 | } 67 | else if(root -> data == k) { 68 | return "exist"; 69 | } 70 | else { 71 | return find_help(root -> right, k); 72 | } 73 | } 74 | string find(Node* root, string k) { 75 | return find_help(root, k); 76 | } 77 | 78 | Node* getmin(Node* root) { 79 | struct Node* cur = root; 80 | while(cur -> left != nullptr) { 81 | cur = cur -> left; 82 | } 83 | return cur; 84 | } 85 | Node* remove(Node* root, string value) { 86 | if(root == nullptr) return root; 87 | if(root -> data > value) { 88 | root -> left = remove(root -> left, value); 89 | } 90 | else if(value > root -> data) { 91 | root -> right = remove(root -> right, value); 92 | } 93 | else { 94 | // node with only one child or no child 95 | if(root -> left == nullptr) { 96 | Node* tmp = root -> right; 97 | free(root); 98 | return tmp; 99 | } 100 | else if(root -> right == nullptr) { 101 | Node *tmp = root -> left; 102 | free(root); 103 | return tmp; 104 | } 105 | // node with two children: Get the inorder successor (smallest 106 | // in the right subtree) 107 | Node* tmp = getmin(root -> right); 108 | // Copy the inorder successor's content to this node 109 | root -> data = tmp -> data; 110 | // Delete the inorder successor 111 | root -> right = remove(root->right, tmp -> data); 112 | } 113 | return root; 114 | } 115 | int main(int argc, char const *argv[]) { 116 | Node* root = nullptr; 117 | root = insert_node(root, "a"); 118 | root = insert_node(root, "ab"); 119 | root = insert_node(root, "abc"); 120 | root = insert_node(root, "abcd"); 121 | root = insert_node(root, "abcde"); 122 | level_order(root); 123 | std::cout << '\n'; 124 | root = remove(root,"a"); 125 | std::cout << "after delete 'a' : " << '\n'; 126 | level_order(root); 127 | std::cout << '\n'; 128 | return 0; 129 | } 130 | -------------------------------------------------------------------------------- /Basic/BinarySearchTree/BST_traverse.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | typedef long long ll; 10 | using namespace std; 11 | 12 | struct Node { 13 | int data; 14 | Node *left; 15 | Node *right; 16 | }; 17 | Node* getNode(int data) { 18 | Node* tmp= new Node; 19 | tmp -> data = data; 20 | tmp -> left = nullptr; 21 | tmp -> right = nullptr; 22 | return tmp; 23 | } 24 | Node* insert_node(Node* root, int data) { 25 | if(root == nullptr) { 26 | return getNode(data); 27 | } 28 | if(root -> data > data) { 29 | root -> left = insert_node(root -> left, data); 30 | } 31 | else { 32 | root -> right = insert_node(root -> right, data); 33 | } 34 | return root; 35 | } 36 | // Inorder 37 | void traverse(Node* root) { 38 | if(root == nullptr) { 39 | return ; 40 | } 41 | traverse(root -> left); 42 | std::cout << root -> data << ' '; 43 | traverse(root -> right); 44 | } 45 | // preorder 46 | void pre_order(Node* root) { 47 | if(root == nullptr) { 48 | return; 49 | } 50 | std::cout << root -> data << ' '; 51 | pre_order(root -> left); 52 | pre_order(root -> right); 53 | } 54 | // level order 55 | void level_order(Node* root) { 56 | queueque; 57 | que.push(root); 58 | que.push(getNode(-1)); 59 | while(!que.empty()) { 60 | Node* tmp = que.front(); 61 | que.pop(); 62 | if(!que.empty() && tmp -> data == -1) { 63 | std::cout << '\n'; 64 | que.push(tmp); 65 | } 66 | else if(tmp -> data != -1) { 67 | std::cout << tmp -> data << ' '; 68 | } 69 | if(tmp -> left) { 70 | que.push(tmp -> left); 71 | } 72 | if(tmp -> right) { 73 | que.push(tmp -> right); 74 | } 75 | } 76 | } 77 | int main(int argc, char const *argv[]) { 78 | Node* root = nullptr; 79 | root = insert_node(root, 11); 80 | root = insert_node(root, 5); 81 | root = insert_node(root, 3); 82 | root = insert_node(root, 10); 83 | root = insert_node(root, 18); 84 | root = insert_node(root, 14); 85 | root = insert_node(root, 1); 86 | root = insert_node(root ,7); 87 | std::cout << "Inorder: "; 88 | traverse(root); 89 | std::cout << '\n'; 90 | std::cout << "Preorder: "; 91 | pre_order(root); 92 | std::cout << '\n'; 93 | std::cout << "Level order: \n "; 94 | level_order(root); 95 | std::cout << '\n'; 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /Basic/BinarySearchTree/Banlancing of BST.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | typedef long long ll; 10 | using namespace std; 11 | 12 | /* 13 | convert a left unbalanced BST to a balanced BST 14 | */ 15 | struct Node { 16 | int data; 17 | Node *left, *right; 18 | }; 19 | void storeBSTNodes(Node* root, vector&nodes) { 20 | if(root == nullptr) { 21 | return ; 22 | } 23 | storeBSTNodes(root -> left, nodes); 24 | nodes.push_back(root); 25 | storeBSTNodes(root -> right, nodes); 26 | } 27 | Node* build(vector&nodes, int left, int right) { 28 | if(left > right) { 29 | return nullptr; 30 | } 31 | int mid = (left + right) >> 1; 32 | Node *root = nodes[mid]; 33 | root -> left = build(nodes,left, mid - 1); 34 | root -> right = build(nodes, mid + 1, right); 35 | return root; 36 | } 37 | Node* buildTree(Node* root) { 38 | vectornodes; 39 | storeBSTNodes(root, nodes); 40 | int n = nodes.size(); 41 | Node* rt = build(nodes, 0, n - 1); 42 | return rt; 43 | } 44 | Node* create(int data) { 45 | Node* node = new Node; 46 | node -> data = data; 47 | node -> left = nullptr; 48 | node -> right = nullptr; 49 | return node; 50 | } 51 | // level order 52 | void level_order(Node* root) { 53 | queueque; 54 | que.push(root); 55 | que.push(create(-1)); 56 | while(!que.empty()) { 57 | Node* tmp = que.front(); 58 | que.pop(); 59 | if(!que.empty() && tmp -> data == -1) { 60 | std::cout << '\n'; 61 | que.push(tmp); 62 | } 63 | else if(tmp -> data != -1) { 64 | std::cout << tmp -> data << ' '; 65 | } 66 | if(tmp -> left) { 67 | que.push(tmp -> left); 68 | } 69 | if(tmp -> right) { 70 | que.push(tmp -> right); 71 | } 72 | } 73 | } 74 | int main(int argc, char const *argv[]) { 75 | /* Constructed skewed binary tree is 76 | 10 77 | / 78 | 8 79 | / 80 | 7 81 | / 82 | 6 83 | / 84 | 5 */ 85 | Node* root = create(10); 86 | root -> left = create(8); 87 | root -> left -> left = create(7); 88 | root -> left -> left -> left = create(6); 89 | root -> left -> left -> left -> left = create(5); 90 | 91 | root = buildTree(root); 92 | std::cout << "Pre order: " << '\n'; 93 | level_order(root); 94 | return 0; 95 | } 96 | -------------------------------------------------------------------------------- /Basic/ConvexHullTrick.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzyrapx/Algorithmic_Template/6000f22159c74773ee3a9be329b17f7cf278494b/Basic/ConvexHullTrick.cpp -------------------------------------------------------------------------------- /Basic/DFS/dfs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzyrapx/Algorithmic_Template/6000f22159c74773ee3a9be329b17f7cf278494b/Basic/DFS/dfs -------------------------------------------------------------------------------- /Basic/DFS/dfs.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | const int maxn = 100010; 6 | vector> >graph(maxn); 7 | vectorvis(maxn, 0); 8 | vectordist(maxn, 0); 9 | 10 | void dfs(long long cur) 11 | { 12 | vis[cur] = 1; 13 | for(auto x : graph[cur]) { 14 | if(vis[x.first] == true) continue; 15 | dist[x.first] = dist[cur] + x.second; 16 | dfs(x.first); 17 | } 18 | } 19 | 20 | int main(){ 21 | int n; // number of node 22 | int m; // number of edge 23 | std::cin >> n >> m; 24 | for(int i = 0;i < m; i++) { 25 | long long u, v, val; 26 | cin >> u >> v >> val; 27 | // undirected graph 28 | graph[u].push_back(make_pair(v, val)); 29 | graph[v].push_back(make_pair(u, val)); 30 | } 31 | dfs(1); 32 | cout << "distance from node 1 to other node:" << endl; 33 | for(int i = 1; i<= n; i++) { 34 | std::cout << dist[i] << " "; 35 | } 36 | cout << endl; 37 | return 0; 38 | } -------------------------------------------------------------------------------- /Basic/DFS/dfs.py: -------------------------------------------------------------------------------- 1 | #conding: utf-8 2 | 3 | __author_ = "LzyRapx" 4 | 5 | from collections import defaultdict 6 | 7 | class Graph: 8 | 9 | # constructor 10 | def __init__(self): 11 | # default dict to store graph 12 | self.graph = defaultdict(list) 13 | def addEdge(self, u, v): 14 | self.graph[u].append(v) 15 | 16 | # A function used by DFS 17 | def DFSutil(self,v,visited): 18 | visited[v] = True 19 | print v 20 | 21 | for i in self.graph[v]: 22 | if visited[i] is False: 23 | self.DFSutil(i, visited) 24 | # main DFS traversal 25 | 26 | def dfs(self, v): 27 | # first to mark all vertices as not visited 28 | visited = [False] * (len(self.graph)) 29 | 30 | # DFS traversal 31 | self.DFSutil(v, visited) 32 | 33 | if __name__ == '__main__': 34 | g = Graph() 35 | g.addEdge(0,1) 36 | g.addEdge(0,2) 37 | g.addEdge(1,2) 38 | g.addEdge(2,3) 39 | g.addEdge(3,3) 40 | g.addEdge(2,0) 41 | 42 | print "DFS starting from vextex 2:" 43 | g.dfs(2) -------------------------------------------------------------------------------- /Black_magic/&与%效率.txt: -------------------------------------------------------------------------------- 1 | /* &取代% 2^n用& */ 2 | int main(int argc, char* argv[]) 3 | { 4 | int a = 0x111; 5 | int b = 0x222; 6 | int c = 0; 7 | int d = 0; 8 | c = a & (b-1); 9 | d = a % b; 10 | return 0; 11 | } 12 | 13 | 看反汇编的结果: 14 | 15 | 13: c = a & (b-1); 16 | 00401044 mov eax,dword ptr [ebp-8] 17 | 00401047 sub eax,1 18 | 0040104A mov ecx,dword ptr [ebp-4] 19 | 0040104D and ecx,eax 20 | 0040104F mov dword ptr [ebp-0Ch],ecx 21 | 14: d = a % b; 22 | 00401052 mov eax,dword ptr [ebp-4] 23 | 00401055 cdq 24 | 00401056 idiv eax,dword ptr [ebp-8] 25 | 00401059 mov dword ptr [ebp-10h],edx 26 | 27 | 可以看到,&操作用了:3mov+1and+1sub %操作用了:2mov+1cdp+1idiv 28 | 我们可以查阅Coding_ASM_-_Intel_Instruction_Set_Codes_and_Cycles资料,发现前者只需5个CPU周期, 29 | 而后者至少需要26个CPU周期(注意,是最少!!!) 效率显而易见。所以以后自己在写的时候,也可以使用前者的写法。 30 | -------------------------------------------------------------------------------- /Black_magic/O(1)快速乘.cpp: -------------------------------------------------------------------------------- 1 | // 求两个数相乘超过long long取摸的快速运算O(1) 2 | inline ll mul_mod(ll a, ll b, ll mod) { 3 | assert(0 <= a && a < mod); 4 | assert(0 <= b && b < mod); 5 | if (mod < int(1e9)) return a * b % mod; 6 | ll k = (ll)((long double)a * b / mod); 7 | ll ans = a * b - k * mod; 8 | ans %= mod; 9 | if (ans < 0) ans += mod; 10 | return ans; 11 | } 12 | -------------------------------------------------------------------------------- /Black_magic/bitset.h: -------------------------------------------------------------------------------- 1 | #define setbit(x, p) ((x)[(p) >> 5] |= 1u << ((p) & 31)) 2 | #define getbit(x, p) ((x)[(p) >> 5] >> ((p) & 31) & 1) -------------------------------------------------------------------------------- /Black_magic/pb_ds(笔记).txt: -------------------------------------------------------------------------------- 1 | //http://blog.csdn.net/wmdcstdio/article/details/44596305 2 | 3 | 1:COGS 2.旅行计划 4 | 题目地址: 5 | http://cogs.pro/cogs/problem/problem.php?pid=2 6 | 求起点到所有点的最短路,可以用pb_ds中的priority_queue优化Dijkstra 7 | 代码: 8 | http://cogs.pro/cogs/submit/code.php?id=149462 9 | tips: 10 | ①声明格式必须是__gnu_pbds::priority_queue,因为STL里还有另一个priority_queue 11 | ②pb_ds包含的这些堆的迭代器是point_iterator而非iterator(见代码16行) 12 | ③push函数有返回值,返回指向插入元素的迭代器 13 | ④可以用Q.modify(iter,val)这样的用法(iter是迭代器,val是新值)来修改堆中元素,不必像用原先那种priority_queue时那样非常奇怪地新插元素再记used数组 14 | 15 | 2:BZOJ 3040.最短路(road) 16 | 题目地址: 17 | http://www.lydsy.com:808/JudgeOnline/problem.php?id=3040 18 | 李煜东出的题,猥琐地卡堆优化Dijkstra的堆效率,一般堆过不去,出题人给的题解是用Fibonacci堆,我们可以用pb_ds中的配对堆(标签:pairing_heap_tag) 19 | 或thin_heap(据说像是Fibonacci堆的玩意,标签:thin_heap_tag)通过 20 | 代码: 21 | http://fayaa.com/code/view/28244/ 22 | 用邻接表写的,不同于上一题的vector存边 23 | 24 | 3:COGS 1829/Tyvj 1728.普通平衡树 25 | 题目地址: 26 | http://cogs.pro/cogs/problem/problem.php?pid=1829 27 | 需要实现一个支持点插入,点删除,查询rank,求第k大,求前驱/后继的数据结构 28 | 正好可以用pb_ds中的tree实现 29 | pb_ds中tree的功能:set/map支持的所有功能,还包括查询rank,求第k大,按值分割(把值>=x的割到另一棵树中),合并值域不相交的两棵树 30 | 为了实现查询rank和求第k大,必须加上tree_order_statistics_node_update 31 | 代码: 32 | http://cogs.pro/cogs/submit/code.php?id=149421 33 | tips: 34 | ①null_mapped_type是用来占位的,如果它是一个真正的数据类型那就是map,如果像这样就是set。在一些编译器上(如COGS的编译器)必须用null_mapped_type,在另一些编译器上必须用null_type 35 | ②即使键类型是long long,你仍然可以强行把比较器定义成less或者greater,当然会出bug 36 | ③pb_ds不资瓷类似multiset/multimap的玩意,你必须自行搞一个偏移量。我的方法是把每个元素乘以2^20后加上偏移量,偏移量是‘当前重复了几次’,再用一个map来维护“每个元素出现了几次”,前驱后继直接在map上计算 37 | 38 | 4:COGS 314.[NOI2004]郁闷的出纳员 39 | 题目地址: 40 | http://cogs.pro/cogs/problem/problem.php?pid=314 41 | 要求实现:点插入,求第k大,删除小于某个值的元素(需要记录删了多少) 42 | “删除小于某个值的元素”用split实现,用greater比较,删除的命令类似于T.split(low,TE),其中TE是一棵无用的树 43 | 代码: 44 | http://cogs.pro/cogs/submit/code.php?id=149424 45 | tips:find_by_order和order_of_key中的“order”都是从0开始数的 46 | 47 | 5:COGS 194.[HAOI2008]排名系统 48 | 题目地址: 49 | http://cogs.pro/cogs/problem/problem.php?pid=197 50 | 要求:点插入/更新,查询rank,求第k大,但元素是一个结构体(名字,得分,更新时间) 51 | 用到了pb_ds中的tree和hash_table 52 | tree中存放结构体,为了比较我们需要自定义伪函数,所谓伪函数就是一个内部重载了()运算符的class,见代码中的Compare类。对于这道题,我们在Compare类中重载()运算符,实现“<”的功能,并将其放在上几题中greater的位置上。 53 | 需要注意,Compare类中重载()运算符时,一定要在函数体前加一个const(见代码24行花括号前的const),代表该函数不会改变传入的元素,否则会编译失败。 54 | pb_ds中的hash_table作用跟map差不多,有cc_hash_table和gp_hash_table两种,前者是用链表存冲突元素,后者是用试探法解决冲突。 55 | hash_table用法和map类似(广义数组),但注意它的迭代器叫point_iterator而非iterator,和priority_queue一样 56 | 代码: 57 | http://cogs.pro/cogs/submit/code.php?id=149448 -------------------------------------------------------------------------------- /Black_magic/rope.txt: -------------------------------------------------------------------------------- 1 | rope支持什么呢?你可以写一个rope a,然后,把a当作一个字符串,你可以: 2 | 1.在log时间、空间内取a的一个子串 3 | 2.在log时间、空间内将两个串链接起来 4 | 也就是说,这是一个支持查找、插入、删除、剪切、复制的一个超级强大的数据结构。 5 | 你甚至可以用一个rope来管理长达几百M的字符串却只占用十几个K的内存, 6 | 所有的操作用时几乎和串的长度无关。 7 | 8 | 它是怎么实现的?? 9 | 我查了一下stl中的文档,参考了一下wikipedia(rope,computer science), 10 | 终于弄明白了它的原理。 11 | 它就是一个可持久化(只读)的平衡树! 12 | 这个树分为四种节点,其中通常情况下只使用两种节点: 13 | 叶节点(代表一小段字符串) 14 | 内节点(表示它左右两个子树的链接,内节点本身不存储数据) 15 | 对于任何操作,它从不修改已有的值,而是建立新的节点。 16 | 它的平衡策略很特殊,大体来说,如果一个节点所在子树的高度是h, 17 | 它代表的串的长度达到了fib(h),就说它是平衡的。 18 | 一般情况,并不管节点是否平衡,使用最直接的操作方式。 19 | 当它在发现某一个树的高度超过给定值之后,在忍无可忍的情况下,进行一次”平衡“操作, 20 | 利用某个特殊的策略(有点像fibheap中的consolidate操作,不过它是以高度为关键字的), 21 | 拼凑出尽量多的平衡节点出来。 22 | 具体的操作过程我看了之后感觉有点晕,并且严重怀疑它背后的数学证明。 23 | 但大量实践雄辩地证明了:这个策略工作地非常好。 -------------------------------------------------------------------------------- /Black_magic/扩栈.cpp: -------------------------------------------------------------------------------- 1 | /* 手工扩栈 */ 2 | 3 | /* C++ */ 4 | #pragma comment(linker, "/STACK:102400000,102400000") 5 | 6 | /* G++ */ 7 | int size = 256 << 20; // 256MB 8 | char *p = (char*)malloc(size) + size; 9 | __asm__("movl %0, %%esp\n" :: "r"(p)); 10 | -------------------------------------------------------------------------------- /Class/Frac.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | using T = long long; 5 | class Frac { 6 | private: 7 | void simply() { 8 | T g = __gcd(num, den); 9 | num /= g; 10 | den /= g; 11 | if (den < T(0)) { 12 | den = -den; 13 | num = -num; 14 | } 15 | } 16 | 17 | public: 18 | T num, den; 19 | Frac(const T& t = 0, const T& s = 1) : num(t), den(s) { simply(); } 20 | double to_double() const { return (double)num / den; } 21 | long double to_ldouble() const { return (long double)num / den; } 22 | friend const Frac operator- (const Frac& t) { 23 | auto ans = t; 24 | ans.num = -ans.num; 25 | return ans; 26 | } 27 | friend const Frac abs(const Frac& t) { 28 | auto ans = t; 29 | if (ans.num < T(0)) ans.num = -ans.num; 30 | return ans; 31 | } 32 | friend ostream& operator<< (ostream& out, const Frac& t) { 33 | out << t.num << "/" << t.den; 34 | return out; 35 | } 36 | friend const Frac operator+ (const Frac& t, const Frac& s) { 37 | auto ans = t; 38 | ans.num = ans.num * s.den + s.num * ans.den; 39 | ans.den *= s.den; 40 | ans.simply(); 41 | return ans; 42 | } 43 | friend const Frac operator- (const Frac& t, const Frac& s) { 44 | return t + (-s); 45 | } 46 | friend const Frac operator* (const Frac& t, const Frac& s) { 47 | auto ans = t; 48 | ans.num *= s.num; 49 | ans.den *= s.den; 50 | ans.simply(); 51 | return ans; 52 | } 53 | friend const Frac operator/ (const Frac& t, const Frac& s) { 54 | if (s == T(0)) throw; 55 | auto ans = s; 56 | swap(ans.num, ans.den); 57 | return t * ans; 58 | } 59 | friend Frac& operator+= (Frac& t, const Frac& s) { 60 | return t = t + s; 61 | } 62 | friend Frac& operator-= (Frac& t, const Frac& s) { 63 | return t = t - s; 64 | } 65 | friend Frac& operator*= (Frac& t, const Frac& s) { 66 | return t = t * s; 67 | } 68 | friend Frac& operator/= (Frac& t, const Frac& s) { 69 | return t = t / s; 70 | } 71 | friend bool operator< (const Frac& t, const Frac& s) { 72 | return t.num * s.den < s.num * t.den; 73 | } 74 | friend bool operator> (const Frac& t, const Frac& s) { 75 | return s < t; 76 | } 77 | friend bool operator== (const Frac& t, const Frac& s) { 78 | return t.num == s.num && t.den == s.den; 79 | } 80 | friend bool operator!= (const Frac& t, const Frac& s) { 81 | return !(t == s); 82 | } 83 | friend bool operator<= (const Frac& t, const Frac& s) { 84 | return t < s || t == s; 85 | } 86 | friend bool operator>= (const Frac& t, const Frac& s) { 87 | return t > s || t == s; 88 | } 89 | }; 90 | 91 | int main(int argc, char const *argv[]) { 92 | 93 | // int a,b; 94 | // std::cin >> a >> b; 95 | Frac ans = Frac(1,3) + Frac(1,3); 96 | Frac res = Frac(2,3) + Frac(1,3); 97 | std::cout << ans << '\n'; 98 | std::cout << res << '\n'; 99 | std::cout << Frac(1,3) << endl; 100 | return 0; 101 | } 102 | -------------------------------------------------------------------------------- /Class/对拍.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | int main() 5 | { 6 | int t=1; 7 | while(1) 8 | { 9 | t--; 10 | // system("data.exe > data.txt"); 11 | // system("biaoda.exe < data.txt > biaoda.txt"); 12 | // system("test.exe < data.txt > test.txt"); 13 | if(system("fc test.txt biaoda.txt")) break; //对拍test.txt 和 biaoda.txt 14 | } 15 | 16 | return 0; 17 | } 18 | 19 | //------------------------------------------------------------------// 20 | #include 21 | using namespace std; 22 | #define maxn 1000010 23 | char ans[maxn][55]; 24 | char ac[maxn][55]; 25 | char s[55]; 26 | int main() { 27 | int a=0,b=0; 28 | freopen("ac.txt","r",stdin); 29 | while(gets(s)) strcpy(ac[a++],s); 30 | freopen("ans.txt","r",stdin); 31 | while(gets(s)) strcpy(ans[b++],s); 32 | if(a!=b) printf("Error!\n"); 33 | else { 34 | int wa=0; 35 | for(int i=0; i 48 | #include 49 | using namespace std; 50 | int main() 51 | { 52 | system("g++ data.cpp -o data -O2"); 53 | system("g++ std.cpp -o std -O2"); 54 | system("g++ my.cpp -o test"); 55 | clock_t st,ed; 56 | for (int i=1;i<=10;i++) 57 | { 58 | printf("%d\n",i); 59 | //Sleep(1000); 60 | system("data"); 61 | system("std"); 62 | st=clock(); 63 | system("test"); 64 | ed=clock(); 65 | printf("Time used:%lfs\n",(double)(ed-st)/CLOCKS_PER_SEC); 66 | int k=system("fc std.out test.out"); 67 | if (k) break; 68 | printf("AC\n"); 69 | } 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /DataStructure/01Tire求区间异或和的最大值.cpp: -------------------------------------------------------------------------------- 1 | // max(XorSum(a_l^r)) 2 | 3 | #include 4 | 5 | using namespace std; 6 | const int MAX = 1e6 + 100; 7 | int bas[35]; 8 | const int INF = 2147483645; 9 | struct Trie { 10 | int nxt[MAX << 2][2]; 11 | int l[MAX << 2]; 12 | int cnt; 13 | int ansl, ansr, ansv; 14 | void init() { 15 | cnt = 0; 16 | memset(nxt[0], 0, sizeof(nxt[0])); 17 | memset(l, 0x3f3f3f3f, sizeof(l)); 18 | ansv = 0; 19 | } 20 | int create() { 21 | cnt++; 22 | memset(nxt[cnt], 0, sizeof(nxt[cnt])); 23 | return cnt; 24 | } 25 | void insert(int id, int x) { 26 | int y = 0; 27 | for (int i = 30; i >= 0; i--) { 28 | int t = x & bas[i]; 29 | t >>= i; 30 | if (!nxt[y][t]) { 31 | nxt[y][t] = create(); 32 | } 33 | y = nxt[y][t]; 34 | } 35 | l[y] = min(l[y], id); 36 | } 37 | void query(int id, int x) { 38 | int y = 0; 39 | int res = 0; 40 | for (int i = 30; i >= 0; i--) { 41 | int t = x & bas[i]; 42 | t >>= i; 43 | if (nxt[y][!t]) { 44 | y = nxt[y][!t]; 45 | res += bas[i]; 46 | } else { 47 | y = nxt[y][t]; 48 | } 49 | } 50 | if (res == ansv) { 51 | if (l[y] < ansl) { 52 | ansl = l[y]; 53 | ansr = id; 54 | } 55 | } else if (res > ansv) { 56 | ansv = res; 57 | ansl = l[y]; 58 | ansr = id; 59 | } 60 | } 61 | void print(int id) { 62 | printf("Case #%d:\n%d %d\n", id, ansl + 1, ansr); // 区间 63 | std::cout << "max xor sum = " << ansv << '\n'; 64 | } 65 | } trie; 66 | 67 | void init() { 68 | bas[0] = 1; 69 | for (int i = 1; i <= 30; i++) { 70 | bas[i] = bas[i - 1] << 1; 71 | } 72 | } 73 | 74 | int main(int argc, char const *argv[]) { 75 | init(); 76 | int n, Cas; 77 | scanf("%d", &Cas); 78 | for (int i = 1; i <= Cas; i++) { 79 | trie.init(); 80 | trie.insert(0, 0); 81 | scanf("%d", &n); 82 | int sum = 0; 83 | for (int j = 1; j <= n; j++) { 84 | int ai; 85 | scanf("%d", &ai); 86 | sum ^= ai; 87 | trie.query(j, sum); 88 | trie.insert(j, sum); 89 | } 90 | trie.print(i); 91 | } 92 | return 0; 93 | } 94 | -------------------------------------------------------------------------------- /DataStructure/CDQ分治.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | CDQ分治解决高维数点问题 4 | 以经典的陌上花开例题为例~ 5 | */ 6 | #include 7 | using namespace std; 8 | typedef long long ll; 9 | const int maxn = 200010; 10 | const int mod = 1e9 + 7; 11 | 12 | // https://www.lydsy.com/JudgeOnline/problem.php?id=3262 13 | // 一朵花的级别是它拥有的美丽能超过的花的数量 14 | // 统计评级为 0...n-1的每级花的数量 15 | // solution : O(n*logn*logn) 16 | 17 | int n,k; 18 | 19 | int s[maxn]; 20 | int ans[maxn]; 21 | 22 | struct Query 23 | { 24 | int x,y,z; 25 | int ans,cnt; 26 | }a[maxn],q[maxn]; 27 | 28 | inline int lowbit(int x) 29 | { 30 | return x&(-x); 31 | } 32 | void update(int pos,int val) 33 | { 34 | while(pos <= k) { 35 | s[pos] += val; 36 | pos += lowbit(pos); 37 | } 38 | } 39 | int query(int pos) 40 | { 41 | int res = 0; 42 | while(pos > 0) { 43 | res += s[pos]; 44 | pos -= lowbit(pos); 45 | } 46 | return res; 47 | } 48 | 49 | bool cmpy(Query a, Query b) 50 | { 51 | if(a.y == b.y) return a.z < b.z; 52 | return a.y < b.y; 53 | } 54 | 55 | void cdq(int l, int r) 56 | { 57 | if(l >= r) return; 58 | int mid = (l + r) >> 1; 59 | cdq(l, mid); 60 | cdq(mid + 1, r); 61 | // 每次把平分的两个数组进行排序 62 | sort(q + l, q + mid + 1, cmpy); 63 | sort(q + mid + 1, q + r + 1, cmpy); 64 | 65 | // 然后扫一遍. 66 | // 因为排过序. 67 | // 所以如果对于[low,mid]里的 i 对[mid+1,r]里的 j 有贡献的话, 68 | // 那么它对 j+1 也是有贡献的 69 | 70 | // 单独处理前一部分和处理前一部分对后一部分的影响,就是 CDQ 分治 71 | int low = l, high = mid + 1; 72 | for(high = mid + 1; high <= r; high ++) 73 | { 74 | while(low <= mid && q[low].y <= q[high].y) 75 | { 76 | update(q[low].z,q[low].cnt); 77 | low++; 78 | } 79 | // 统计树状数组中所有下标小于等于 q.z 的值之和累加到 q.ans中 80 | q[high].ans += query(q[high].z); 81 | } 82 | // 最后要去掉[l,low-1]的贡献, 相当于撤销操作 83 | // std::cout << "low = " << low << '\n'; 84 | for(int i = l; i < low; i++) { 85 | update(q[i].z ,-q[i].cnt); 86 | } 87 | } 88 | bool cmpx(Query a, Query b) 89 | { 90 | if(a.x == b.x && a.y == b.y) return a.z < b.z; 91 | else if(a.x == b.x) return a.y < b.y; 92 | return a.x < b.x; 93 | } 94 | int main(int argc, char const *argv[]) { 95 | // freopen("in.txt","r",stdin); 96 | std::cin >> n >> k; 97 | for(int i = 1; i <= n; i++) { 98 | std::cin >> a[i].x >> a[i].y >> a[i].z; 99 | } 100 | sort(a + 1, a + n + 1, cmpx); // 排序去掉其中一维 101 | int cnt = 0; 102 | int id = 0; 103 | for(int i = 1; i <= n; i++) { 104 | cnt ++; // 对于完全相同的点可以先合并起来, 后面统计在加起来=(q[i].cnt - 1) 105 | if(a[i].x != a[i+1].x || a[i].y != a[i+1].y || a[i].z != a[i+1].z) 106 | { 107 | q[++id] = a[i]; 108 | q[id].cnt = cnt; 109 | cnt = 0; 110 | } 111 | } 112 | // std::cout << "id = " << id << '\n'; 113 | cdq(1,id); 114 | // 最后统计评级为0...n-1的每级花的数量,n-1最高,即其他花都不能比 115 | for(int i = 1; i <= id; i++) { 116 | // std::cout << "ans = " << q[i].ans << '\n'; 117 | ans[q[i].ans + (q[i].cnt - 1)] += q[i].cnt; // (q[i].cnt - 1) 表示被合并的,和 i 一样的其它的花,不算自己 118 | } 119 | for(int i = 0; i < n; i++) { 120 | std::cout << ans[i] << '\n'; 121 | } 122 | return 0; 123 | } 124 | -------------------------------------------------------------------------------- /DataStructure/Cartesian_Tree.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 笛卡尔树: 3 | 1.树中的元素满足二叉搜索树性质,要求按照中序遍历得到的序列为原数组序列(左儿子的key值小于自己,右儿子的key值大于自己)。 4 | 2.树中节点满足堆性质,节点的val值要大于其左右子节点的val值。 5 | */ 6 | 7 | #include 8 | 9 | using namespace std; 10 | 11 | int main(int argc, char const *argv[]) 12 | { 13 | /* code */ 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /DataStructure/Circle-Square-Tree Maximum independent set.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 圆方树 & 仙人掌学习笔记: https://www.cnblogs.com/cjyyb/p/9098400.html 3 | circle-square-tree Maximum independent set. 4 | 圆方树最大独立集. 5 | 最大独立集:在无向图中选出若干个点,这些点互相没有边连接,并使取出的点尽量多. 6 | */ 7 | #include 8 | using namespace std; 9 | const int maxn = 1e5 + 100; 10 | vector E1[maxn], ET[maxn]; 11 | int m, n, N, fa[maxn], dp[maxn][2]; 12 | int len[maxn], dfn[maxn], dfs_clock; 13 | bool inCircle[maxn]; 14 | int dp2[maxn][2]; 15 | inline void addEdge1(int x, int y) { E1[x].push_back(y); } 16 | inline void addEdgeT(int x, int y) { ET[x].push_back(y); } 17 | 18 | void input() { 19 | cin >> n >> m; 20 | N = n; 21 | for (int i = 0; i < m; i++) { 22 | int u, v; 23 | cin >> u >> v; 24 | addEdge1(u, v); 25 | addEdge1(v, u); 26 | } 27 | } 28 | 29 | void tarjan(int u) { 30 | dfn[u] = ++dfs_clock; 31 | for (int i = 0; i < (int)E1[u].size(); i++) { 32 | int v = E1[u][i]; 33 | if (v == fa[u]) continue; 34 | if (!dfn[v]) { 35 | fa[v] = u; 36 | tarjan(v); 37 | } 38 | else if (dfn[v] < dfn[u]) { 39 | n++; 40 | len[n] = dfn[u] - dfn[v] + 1; 41 | fa[n] = v; 42 | addEdgeT(v, n); 43 | int temp = u; 44 | while (temp != v) { 45 | inCircle[temp] = true; 46 | addEdgeT(n, temp); 47 | temp = fa[temp]; 48 | } 49 | } 50 | } 51 | 52 | if (!inCircle[u]) { 53 | addEdgeT(fa[u], u); 54 | } 55 | dfs_clock--; 56 | } 57 | void work(int x) { 58 | int sz = ET[x].size(); 59 | if (sz == 2) { 60 | int son1 = ET[x][0]; 61 | int son2 = ET[x][1]; 62 | dp[x][0] = dp[son1][0] + dp[son2][0]; 63 | dp[x][1] = max(dp[son1][0] + dp[son2][0], 64 | max(dp[son1][0] + dp[son2][1], dp[son1][1] + dp[son2][0])); 65 | return; 66 | } 67 | dp2[0][0] = dp[ET[x][0]][0]; 68 | dp2[0][1] = 0; 69 | for (int i = 1; i < sz; i++) { 70 | dp2[i][0] = max(dp2[i - 1][0], dp2[i - 1][1]) + dp[ET[x][i]][0]; 71 | dp2[i][1] = dp2[i - 1][0] + dp[ET[x][i]][1]; 72 | } 73 | 74 | dp[x][0] = dp2[sz - 1][0]; 75 | dp[x][1] = dp2[sz - 1][0]; 76 | dp2[sz][0] = dp2[sz][1] = 0; 77 | 78 | for (int i = sz - 1; i >= 0; i--) { 79 | dp2[i][0] = max(dp2[i + 1][0], dp2[i + 1][1]) + dp[ET[x][i]][0]; 80 | dp2[i][1] = dp2[i + 1][0] + dp[ET[x][i]][1]; 81 | } 82 | dp[x][1] = max(dp[x][1], max(dp2[0][0], dp2[0][1])); 83 | } 84 | void dfs(int u) { 85 | dp[u][0] = 0; 86 | dp[u][1] = 1; 87 | if (u > N) dp[u][0] = 0; 88 | for (int i = 0; i < (int)ET[u].size(); i++) { 89 | int v = ET[u][i]; 90 | dfs(v); 91 | if (u <= N) { 92 | dp[u][0] += max(dp[v][1], dp[v][0]); 93 | dp[u][1] += dp[v][0]; 94 | } 95 | } 96 | if (u > N) work(u); 97 | } 98 | int main() { 99 | input(); 100 | tarjan(1); 101 | dfs(1); 102 | /* 103 | dp[u][0]表示只考虑 u的子树,u点不选的方案个数. 104 | dp[u][1]表示只考虑 u的子树,选了u点的方案个数. 105 | 然后正常 DP,然后每次DP到所有环中离根最近的那个点时,单独拉出来算一下就可以了. 106 | */ 107 | cout << max(dp[1][0], dp[1][1]) << endl; 108 | return 0; 109 | } 110 | -------------------------------------------------------------------------------- /DataStructure/DLX.cpp: -------------------------------------------------------------------------------- 1 | /* DLX O(?) */ 2 | 3 | 4 | const int maxn=110; 5 | const int maxnode=110; 6 | const int maxr=110; 7 | 8 | struct DLX{ 9 | int n,sz; 10 | int S[maxn]; 11 | 12 | int row[maxnode],col[maxnode]; 13 | int L[maxnode],R[maxnode],U[maxnode],D[maxnode]; 14 | 15 | int ansd,ans[maxr]; 16 | 17 | void init(int n){ 18 | this->n = n; 19 | for(int i = 0 ; i <= n ;i++){ 20 | U[i] = i; 21 | D[i] = i; 22 | L[i] = i-1; 23 | R[i] = i+1; 24 | } 25 | R[n] = 0; 26 | L[0] = n; 27 | sz = n+1; 28 | mem(S,0); 29 | } 30 | 31 | void addRow(int r , vector columns){ 32 | int first = sz; 33 | for(int i = 0 ; i < columns.size() ; i++){ 34 | int c= columns[i]; 35 | L[sz] = sz - 1; 36 | R[sz] = sz +1; 37 | D[sz] = c; 38 | U[sz] = U[c]; 39 | D[U[c]] = sz ; 40 | U[c] = sz; 41 | row[sz] = r; 42 | col[sz] = c; 43 | S[c]++; 44 | sz++; 45 | } 46 | R[sz-1] = first; 47 | L[first] = sz - 1; 48 | } 49 | #define FOR(i,A,s) for(int i = A[s] ; i != s; i = A[i]) 50 | void remove(int c){ 51 | L[R[c]] = L[c]; 52 | R[L[c]] = R[c]; 53 | FOR(i,D,c){ 54 | FOR(j,R,i){ 55 | U[D[j]] = U[j]; 56 | D[U[j]] = U[j] ; 57 | D[U[j]] = D[j] ; 58 | --S[col[j]]; 59 | } 60 | } 61 | } 62 | 63 | void restore(int c){ 64 | FOR(i,U,c){ 65 | FOR(j,L,i){ 66 | ++S[col[j]]; 67 | U[D[j]] = j; 68 | D[U[j]] = j; 69 | } 70 | } 71 | L[R[c]] = c; 72 | R[L[c]] = c; 73 | } 74 | 75 | bool dfs(int d){ 76 | if(R[0] == 0){ 77 | ansd = d; 78 | return true; 79 | } 80 | int c= R[0]; 81 | FOR(i,R,0) if(S[i] < S[c]) c = i; 82 | remove(c); 83 | FOR(i,D,c){ 84 | ans[d] = row[i]; 85 | FOR(j,R,i) remove(col[j]); 86 | if(dfs(d+1)) return true; 87 | FOR(j,L,i) restore(col[j]); 88 | } 89 | restore(c); 90 | return false; 91 | } 92 | 93 | bool solve(vector & v){ 94 | v.clear(); 95 | if(!dfs(0)) return false; 96 | for(int i = 0 ; i < ansd ; i++) v.push_back(ans[i]); 97 | return true; 98 | } 99 | }solver; 100 | -------------------------------------------------------------------------------- /DataStructure/HASH.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | HASH 3 | 数字HASH,开散列,邻接表 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | typedef long long ll; 10 | const int MOD = 4001, STA = 1000010; // MOD为表长,STA为表大小 11 | 12 | struct Hash { 13 | int first[MOD], next[STA], sz; 14 | ll f[STA], sta[STA]; // sta[]存放状态,f[]为对应状态的权值 15 | void init() { 16 | sz = 0; 17 | memset(first, -1, sizeof(first)); 18 | } 19 | int find_add(ll st, ll ans) { //查找,如果未查找到则添加 20 | int i, u = st % MOD; 21 | for (i = first[u]; i != -1; i = next[i]) { 22 | if (sta[i] == st) { 23 | f[i] += ans; //状态累加,注意啦 24 | return 1; //已存在状态 25 | } 26 | } 27 | sta[sz] = st; 28 | f[sz] = ans; 29 | next[sz] = first[u]; 30 | first[u] = sz++; 31 | } 32 | } hs; 33 | -------------------------------------------------------------------------------- /DataStructure/KMP.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: zhaoyang.liang 3 | * @Github: https://github.com/LzyRapx 4 | * @Date: 2019-06-13 00:02:05 5 | */ 6 | 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | int Next[20]; 12 | void get_nextval(char T[], int Next[]) { 13 | int j, k; 14 | j = 0; 15 | Next[0] = -1; 16 | k = -1; 17 | while (T[j + 1] != '\0') { 18 | if (k == -1 || T[j] == T[k]) { 19 | ++j, ++k; 20 | if (T[j] != T[k]) 21 | Next[j] = k; 22 | else 23 | Next[j] = Next[k]; 24 | } else 25 | k = Next[k]; 26 | } 27 | } 28 | 29 | int Index_KMP(char S[], char T[], int pos) { 30 | int i, j; 31 | i = pos - 1; 32 | j = 0; 33 | while (S[i] != '\0' && T[j] != '\0') { 34 | if (j == -1 || S[i] == T[j]) 35 | i++, j++; 36 | else 37 | j = Next[j]; 38 | } 39 | if (T[j] == '\0') 40 | return (i - j); 41 | else 42 | return 0; 43 | } 44 | 45 | int main() { 46 | int m; 47 | char S[20] = "abcdfadabddfa"; 48 | char T[20] = "bc"; 49 | get_nextval(T, Next); 50 | m = Index_KMP(S, T, 1); 51 | printf("%d\n", m); 52 | getchar(); 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /DataStructure/LCA.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: zhaoyang.liang 3 | * @Github: https://github.com/LzyRapx 4 | * @Date: 2019-06-13 00:02:05 5 | */ 6 | 7 | /* LCA */ 8 | 9 | /* 10 | 11 | DFS+ST 12 | 预处理:O(n*logn) 13 | 查询:O(1) 14 | DFS处理: 15 | T=,其中V={A,B,C,D,E,F,G},E={AB,AC,BD,BE,EF,EG},且A为树根。 16 | 则图T的DFS结果为:A->B->D->B->E->F->E->G->E->B->A->C->A 17 | ST处理d[]数组 18 | dis为深度遍历计数 19 | d[]为树遍历节点的深度 20 | E[]为树遍历的节点的标号 21 | R[i]表示E数组中第一个值为i的元素下标 22 | f[i][j]为深度遍历[i,j]区间的最小深度的深度遍历编号 23 | 如果有n个节点,那么E[]和R[]下标范围为2*n-1 24 | rmq下标范围为[1,n] 25 | 注意他们的最近公共祖先为他们本身的情况!!! 26 | 27 | */ 28 | #include 29 | #include 30 | using namespace std; 31 | 32 | const int N = 50000; 33 | struct Edge { 34 | int u, v; 35 | } e[N]; 36 | int first[N], Next[N], f[N][20], d[N], E[N], R[N], vis[N]; 37 | int T, n, m, mt, dis, root; 38 | 39 | void addedge(int a, int b) { 40 | e[mt].u = a; 41 | e[mt].v = b; 42 | Next[mt] = first[a]; 43 | first[a] = mt++; 44 | } 45 | 46 | int Minele(int i, int j) //比较距离来获取下标 47 | { 48 | return d[i] < d[j] ? i : j; 49 | } 50 | 51 | void rmq_init(int n) { 52 | int i, j; 53 | for (i = 1; i <= n; i++) f[i][0] = i; 54 | for (j = 1; (1 << j) <= n; j++) { 55 | for (i = 1; i + (1 << j) - 1 <= n; i++) { 56 | f[i][j] = Minele(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]); 57 | } 58 | } 59 | } 60 | 61 | int rmq(int l, int r) { 62 | int k = 0; 63 | while ((1 << (k + 1)) <= r - l + 1) k++; 64 | return Minele(f[l][k], f[r - (1 << k) + 1][k]); 65 | } 66 | 67 | void dfs(int u, int deep) { 68 | d[dis] = deep; 69 | E[dis] = u; 70 | R[u] = dis++; 71 | int i; 72 | for (i = first[u]; i != -1; i = Next[i]) { 73 | dfs(e[i].v, deep + 1); 74 | d[dis] = deep; 75 | E[dis++] = u; 76 | } 77 | } 78 | 79 | // O(n*logn) 80 | void LCA_Init() { 81 | dis = 1; //初始化为1 82 | dfs(root, 0); //传递根节点和深度 83 | rmq_init(2 * n - 1); //传递E[]和R[]的长度 84 | } 85 | 86 | // o(1) 87 | // 返回a和b节点的最近祖先节点标号,注意他们的最近公共祖先为他们本身的情况 88 | int LCA(int a, int b) { 89 | int left = R[a], right = R[b]; 90 | if (left > right) swap(left, right); 91 | return E[rmq(left, right)]; 92 | } 93 | -------------------------------------------------------------------------------- /DataStructure/LCT.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | const int N = 610000; 8 | 9 | int f[N], son[N][2]; 10 | 11 | int val[N], sum[N], siz[N], mx[N]; 12 | 13 | int rev[N], flag[N]; 14 | 15 | void LCTInit() { 16 | memset(son, 0, sizeof(son)); 17 | memset(f, 0, sizeof(f)); 18 | memset(rev, 0, sizeof(rev)); 19 | memset(val, 0, sizeof(val)); 20 | memset(sum, 0, sizeof(sum)); 21 | memset(flag, 0, sizeof(flag)); 22 | memset(mx, 0, sizeof(mx)); 23 | } 24 | 25 | bool isroot(int x) { return !f[x] || (son[f[x]][0] != x && son[f[x]][1] != x); } 26 | 27 | void reverse(int x) { 28 | if (!x) return; 29 | swap(son[x][0], son[x][1]); 30 | rev[x] ^= 1; 31 | } 32 | 33 | void add(int x, int c) { 34 | if (!x) return; 35 | sum[x] += c * siz[x]; 36 | val[x] += c; 37 | mx[x] += c; 38 | flag[x] += c; 39 | } 40 | 41 | void pb(int x) { 42 | if (rev[x]) { 43 | reverse(son[x][0]); 44 | reverse(son[x][1]); 45 | rev[x] = 0; 46 | } 47 | if (flag[x]) { 48 | add(son[x][0], flag[x]); 49 | add(son[x][1], flag[x]); 50 | flag[x] = 0; 51 | } 52 | } 53 | 54 | inline void up(int x) { 55 | pb(x); 56 | siz[x] = 1; 57 | sum[x] = val[x]; 58 | mx[x] = val[x]; 59 | if (son[x][0]) { 60 | siz[x] += siz[son[x][0]]; 61 | sum[x] += sum[son[x][0]]; 62 | mx[x] = max(mx[x], mx[son[x][0]]); 63 | } 64 | 65 | if (son[x][1]) { 66 | siz[x] += siz[son[x][1]]; 67 | sum[x] += sum[son[x][1]]; 68 | mx[x] = max(mx[x], mx[son[x][1]]); 69 | } 70 | } 71 | 72 | inline void rotate(int x) { 73 | int y = f[x], w = son[y][1] == x; 74 | son[y][w] = son[x][w ^ 1]; 75 | if (son[x][w ^ 1]) f[son[x][w ^ 1]] = y; 76 | if (f[y]) { 77 | int z = f[y]; 78 | if (son[z][0] == y) son[z][0] = x; 79 | if (son[z][1] == y) son[z][1] = x; 80 | } 81 | f[x] = f[y]; 82 | f[y] = x; 83 | son[x][w ^ 1] = y; 84 | up(y); 85 | } 86 | 87 | int tmp[N]; 88 | 89 | void splay(int x) { 90 | int s = 1, i = x, y; 91 | tmp[1] = i; 92 | while (!isroot(i)) tmp[++s] = i = f[i]; 93 | while (s) pb(tmp[s--]); 94 | while (!isroot(x)) { 95 | y = f[x]; 96 | if (!isroot(y)) { 97 | if ((son[f[y]][0] == y) ^ (son[y][0] == x)) 98 | rotate(x); 99 | else 100 | rotate(y); 101 | } 102 | rotate(x); 103 | } 104 | up(x); 105 | } 106 | 107 | // 核心操作,打通x到目前根的一条链 108 | 109 | void access(int x) { 110 | for (int y = 0; x; y = x, x = f[x]) splay(x), son[x][1] = y, up(x); 111 | } 112 | 113 | /* 114 | get the root of the current set 115 | can be used as the union-find set 116 | */ 117 | 118 | int root(int x) { 119 | access(x); 120 | splay(x); 121 | while (son[x][0]) x = son[x][0]; 122 | return x; 123 | } 124 | 125 | void makeroot(int x) { 126 | access(x); 127 | splay(x); 128 | reverse(x); 129 | } 130 | 131 | void link(int x, int y) { 132 | makeroot(x); 133 | f[x] = y; 134 | access(x); 135 | } 136 | 137 | void cutf(int x) { 138 | access(x); 139 | splay(x); 140 | f[son[x][0]] = 0; 141 | son[x][0] = 0; 142 | up(x); 143 | } 144 | 145 | void cut(int x, int y) { 146 | makeroot(x); 147 | cutf(y); 148 | } 149 | 150 | int find(int x) { 151 | access(x); 152 | splay(x); 153 | int y = x; 154 | while (son[y][0]) y = son[y][0]; 155 | return y; 156 | } 157 | 158 | inline int lca(int x, int y) { 159 | int ans; 160 | access(y); 161 | y = 0; 162 | do { 163 | splay(x); 164 | if (!f[x]) ans = x; 165 | x = f[y = x]; 166 | } while (x); 167 | return ans; 168 | } 169 | 170 | int n, m, x, y; 171 | 172 | int main() { 173 | while (cin >> n) { 174 | LCTInit(); 175 | 176 | for (int i = 1; i <= n; i++) siz[i] = 1; 177 | 178 | for (int i = 1; i < n; i++) { 179 | scanf("%d%d", &x, &y); 180 | link(x, y); 181 | } 182 | 183 | for (int i = 1; i <= n; i++) scanf("%d", &val[i]), mx[i] = sum[i] = val[i]; 184 | 185 | int q; 186 | scanf("%d", &q); 187 | 188 | while (q--) { 189 | int ty, z, x, y; 190 | scanf("%d", &ty); 191 | scanf("%d%d", &x, &y); 192 | if (ty == 1) { 193 | if (root(x) == root(y)) { 194 | printf("-1\n"); 195 | continue; 196 | } 197 | link(x, y); 198 | } 199 | if (ty == 2) { 200 | if (root(x) != root(y) || x == y) { 201 | printf("-1\n"); 202 | continue; 203 | } 204 | makeroot(x); 205 | cutf(y); 206 | } 207 | if (ty == 3) { 208 | scanf("%d", &z); 209 | if (root(z) != root(y)) { 210 | printf("-1\n"); 211 | continue; 212 | } 213 | makeroot(y); 214 | access(z); 215 | splay(z); 216 | add(z, x); 217 | } 218 | if (ty == 4) { 219 | if (root(x) != root(y)) { 220 | printf("-1\n"); 221 | continue; 222 | } 223 | makeroot(x); 224 | access(y); 225 | splay(y); 226 | printf("%d\n", mx[y]); 227 | } 228 | } 229 | printf("\n"); 230 | } 231 | } -------------------------------------------------------------------------------- /DataStructure/Splay_Tree - v2.cpp: -------------------------------------------------------------------------------- 1 | 2 | //区间翻转:https://loj.ac/problem/105 3 | 4 | #include 5 | using namespace std; 6 | const int maxn = 100010; 7 | const int maxm = 100010; 8 | int a[maxn]; 9 | int n, m; 10 | namespace SplayTree { 11 | // siz代表节点的sz,fa代表父亲节点,ma代表最大值,rev翻转标记 12 | int siz[maxn], fa[maxn], ma[maxn], rev[maxn], lazy[maxn], val[maxn]; 13 | // lazy 区间+, val 值 14 | // tot代表开新节点的时间戳,root代表splay的树根,ch[i][2],i的左右儿子 15 | int ch[maxn][2], tot, root; 16 | void newnode(int &rt, int father, int k) { 17 | rt = ++tot; 18 | siz[rt] = 1, fa[rt] = father; 19 | ma[rt] = val[rt] = k; 20 | rev[rt] = lazy[rt] = ch[rt][0] = ch[rt][1] = 0; 21 | } 22 | void pushup(int rt) { // pushup 从底向上更新 23 | siz[rt] = 1, ma[rt] = val[rt]; 24 | if (ch[rt][0] != 0) 25 | siz[rt] += siz[ch[rt][0]], ma[rt] = max(ma[rt], ma[ch[rt][0]]); 26 | if (ch[rt][1] != 0) 27 | siz[rt] += siz[ch[rt][1]], ma[rt] = max(ma[rt], ma[ch[rt][1]]); 28 | } 29 | void pushdown(int rt) { // pushdown 从上向下更新 30 | if (!rt) return; 31 | if (lazy[rt]) { //区间+懒惰标记传递 32 | int l = ch[rt][0], r = ch[rt][1]; 33 | if (l != 0) ma[l] += lazy[rt], val[l] += lazy[rt], lazy[l] += lazy[rt]; 34 | if (r != 0) ma[r] += lazy[rt], val[r] += lazy[rt], lazy[r] += lazy[rt]; 35 | lazy[rt] = 0; 36 | } 37 | if (rev[rt]) { // 区间翻转懒惰标记传递 38 | int l = ch[rt][0], r = ch[rt][1]; 39 | if (l != 0) rev[l] ^= 1, swap(ch[l][0], ch[l][1]); 40 | if (r != 0) rev[r] ^= 1, swap(ch[r][0], ch[r][1]); 41 | rev[rt] ^= 1; 42 | } 43 | } 44 | void rotate(int x) { // 旋转,把x转到根节点,kind为1代表右旋,kind为0代表左旋 45 | int y = fa[x], kind = ch[y][1] == x; 46 | pushdown(y), pushdown(x); 47 | ch[y][kind] = ch[x][!kind]; 48 | fa[ch[y][kind]] = y; 49 | ch[x][!kind] = y; 50 | fa[x] = fa[y]; 51 | fa[y] = x; 52 | ch[fa[x]][ch[fa[x]][1] == y] = x; 53 | pushup(y), pushup(x); 54 | } 55 | void splay(int x, int goal) // 伸展操作,把根为r的子树调整为goal 56 | { 57 | while (fa[x] != goal) { 58 | int y = fa[x], z = fa[y]; 59 | if (z == goal) 60 | rotate(x); 61 | else if ((ch[y][1] == x) == (ch[z][1] == y)) 62 | rotate(y), rotate(x); 63 | else 64 | rotate(x), rotate(x); 65 | } 66 | if (goal == 0) root = x; 67 | } 68 | void build(int &rt, int l, int r, int father) { // 建立一颗空的splaytree 69 | if (l > r) return; 70 | int mid = (l + r) / 2; 71 | newnode(rt, father, a[mid]); // 递归申请新节点 72 | build(ch[rt][0], l, mid - 1, rt); 73 | build(ch[rt][1], mid + 1, r, rt); 74 | pushup(rt); 75 | } 76 | int find(int x, int k) { // 查找第k位置在splaytree中的位置 77 | pushdown(x); 78 | int lsum = siz[ch[x][0]] + 1; 79 | if (lsum == k) 80 | return x; 81 | else if (lsum < k) 82 | return find(ch[x][1], k - lsum); 83 | else 84 | return find(ch[x][0], k); 85 | } 86 | void update_val(int l, int r, int v) { // 区间更新+ 87 | splay(find(root, l), 0); 88 | splay(find(root, r + 2), root); 89 | lazy[ch[ch[root][1]][0]] += v; 90 | ma[ch[ch[root][1]][0]] += v; 91 | val[ch[ch[root][1]][0]] += v; 92 | } 93 | void update_rev(int l, int r) { 94 | splay(find(root, l), 0); 95 | splay(find(root, r + 2), root); 96 | int tmp = ch[ch[root][1]][0]; // 现在以tmp为根的splaytree就是l,r区间 97 | rev[tmp] ^= 1; 98 | swap(ch[tmp][0], ch[tmp][1]); 99 | } 100 | int querymax(int l, int r) { // 查询区间最大值 101 | splay(find(root, l), 0); 102 | splay(find(root, r + 2), root); 103 | return ma[ch[ch[root][1]][0]]; 104 | } 105 | void dfs(int x) { 106 | pushdown(x); 107 | if (ch[x][0]) dfs(ch[x][0]); 108 | if (val[x] >= 1 && val[x] <= n) printf("%d ", val[x]); 109 | if (ch[x][1]) dfs(ch[x][1]); 110 | } 111 | } 112 | using namespace SplayTree; 113 | 114 | int main() { 115 | scanf("%d %d", &n, &m); 116 | for (int i = 1; i <= n; i++) a[i] = i; 117 | newnode(root, 0, -1); 118 | newnode(ch[root][1], root, -1); 119 | build(ch[ch[root][1]][0], 1, n, ch[root][1]); 120 | pushup(ch[root][1]); 121 | pushup(root); 122 | for (int i = 1; i <= m; i++) { 123 | int a, b; 124 | scanf("%d%d", &a, &b); 125 | update_rev(a, b); 126 | } 127 | dfs(root); 128 | return 0; 129 | } -------------------------------------------------------------------------------- /DataStructure/merge_sort.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: zhaoyang.liang 3 | * @Github: https://github.com/LzyRapx 4 | * @Date: 2019-06-13 00:02:05 5 | */ 6 | 7 | 8 | /* 9 | merge sort 10 | 求逆序对数量 11 | */ 12 | 13 | #include 14 | #include 15 | using namespace std; 16 | const int N = 500000; 17 | typedef long long ll; 18 | 19 | int num[N], temp[N]; 20 | int n; 21 | 22 | ll sort(int l, int r) { 23 | if (l == r) return 0; 24 | int i, j, k, mid = (l + r) >> 1; 25 | ll ans; 26 | sort(l, mid); 27 | sort(mid + 1, r); 28 | for (i = k = l, j = mid + 1; i <= mid && j <= r;) { 29 | if (num[i] < num[j]) { 30 | ans += j - mid - 1; 31 | temp[k++] = num[i++]; 32 | } else 33 | temp[k++] = num[j++]; 34 | } 35 | while (i <= mid) { 36 | ans += j - mid - 1; 37 | temp[k++] = num[i++]; 38 | } 39 | while (j <= r) temp[k++] = num[j++]; 40 | for (i = l; i <= r; i++) num[i] = temp[i]; 41 | return ans; 42 | } 43 | -------------------------------------------------------------------------------- /Geometry/Geometry3d (Basic).h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | typedef double flt; 5 | 6 | const flt eps = 1e-8; 7 | int sgn(flt x) {return x < -eps ? -1 : x > eps;} 8 | 9 | struct Point { 10 | flt x, y, z; 11 | Point() {} 12 | Point(flt x, flt y, flt z): x(x), y(y), z(z) {} 13 | bool operator < (const Point &rhs) const { 14 | return x < rhs.x || (x == rhs.x && y < rhs.y) || (x == rhs.x && y == rhs.y && z < rhs.z); 15 | } 16 | Point operator + (const Point &rhs) const { 17 | return Point(x + rhs.x, y + rhs.y, z + rhs.z); 18 | } 19 | Point operator - (const Point &rhs) const { 20 | return Point(x - rhs.x, y - rhs.y, z - rhs.z); 21 | } 22 | Point operator * (const flt k) const { 23 | return Point(x * k, y * k, z * k); 24 | } 25 | Point operator / (const flt k) const { 26 | return Point(x / k, y / k, z / k); 27 | } 28 | flt dot(const Point &rhs) const { 29 | return x * rhs.x + y * rhs.y + z * rhs.z; 30 | } 31 | Point det(const Point &rhs) const { 32 | return Point(y * rhs.z - z * rhs.y, z * rhs.x - x * rhs.z, x * rhs.y - y * rhs.x); 33 | } 34 | flt sqrlen() const { 35 | return x * x + y * y + z * z; 36 | } 37 | flt len() const { 38 | return sqrt(sqrlen()); 39 | } 40 | void read() { 41 | scanf("%lf%lf%lf", &x, &y, &z); 42 | } 43 | void print() { 44 | printf("%.10f %.10f %.10f\n", x, y, z); 45 | } 46 | } A, B, C, D; 47 | 48 | // 判断点C是否在直线AB上 49 | bool dotsInline(const Point &A, const Point &B, const Point &C) { 50 | return sgn((B - A).det(C - A).len()) == 0; 51 | } 52 | 53 | // 判断直线AB和CD是否平行 54 | bool is_parallel(const Point &A, const Point &B, const Point &C, const Point &D) { 55 | return sgn((B - A).det(D - C).len()) == 0; 56 | } 57 | 58 | // 判断直线AB和CD的交点, 如果直线异面, 返回的是两直线的垂线在AB上的垂足 59 | // 需要保证AB和CD不平行. 60 | Point intersect(const Point &A, const Point &B, const Point &C, const Point &D) { 61 | Point p0 = (C - A).det(D - C), p1 = (B - A).det(D - C); 62 | return A + (B - A) * (p0.dot(p1) / p1.sqrlen()); 63 | } 64 | -------------------------------------------------------------------------------- /Graph-theory/Connectivity/BCC (multi-version).cpp: -------------------------------------------------------------------------------- 1 | /* 2 | BCC O(E) 3 | tarjan算法 4 | -Node-Biconnected Component 5 | -Edge-Biconnected Component(可以处理重边) 6 | -Edge-Biconnected Component(不能处理重边) 7 | */ 8 | 9 | /* 10 | Node-Biconnected Component 11 | iscut[]为割点集 12 | bcc[]为双连通点集 13 | 割顶的bccno[]无意义 14 | */ 15 | #include 16 | #include 17 | #include 18 | #include 19 | using namespace std; 20 | 21 | const int N = 500000; 22 | struct Edge { 23 | int u, v; 24 | } e[N * N]; 25 | bool iscut[N]; 26 | int first[N], Next[N * N], low[N], pre[N], bccno[N]; 27 | int n, m, mt, dfs_clock, bcnt; 28 | vector bcc[N]; 29 | stack s; 30 | 31 | void addedge(int a, int b) { 32 | e[mt].u = a; 33 | e[mt].v = b; 34 | Next[mt] = first[a]; 35 | first[a] = mt++; 36 | e[mt].u = b; 37 | e[mt].v = a; 38 | Next[mt] = first[b]; 39 | first[b] = mt++; 40 | } 41 | 42 | void dfs(int u, int fa) { 43 | int child = 0; 44 | Edge t; 45 | pre[u] = low[u] = ++dfs_clock; 46 | for (int i = first[u]; i != -1; i = Next[i]) { 47 | child++; 48 | int v = e[i].v; 49 | t.u = u; 50 | t.v = v; 51 | if (!pre[v]) //没有访问过 52 | { 53 | s.push(t); 54 | dfs(v, u); 55 | low[u] = min(low[u], low[v]); 56 | if (low[v] >= pre[u]) //点u为割点 57 | { 58 | iscut[u] = true; 59 | Edge x; 60 | x.u = -1; 61 | bcnt++; 62 | bcc[bcnt].clear(); 63 | while (x.u != u || x.v != v) { 64 | x = s.top(); 65 | s.pop(); 66 | if (bccno[x.u] != bcnt) { 67 | bcc[bcnt].push_back(x.u); 68 | bccno[x.u] = bcnt; 69 | } 70 | if (bccno[x.v] != bcnt) { 71 | bcc[bcnt].push_back(x.v); 72 | bccno[x.v] = bcnt; 73 | } 74 | } 75 | } 76 | } else if (v != fa && pre[v] < pre[u]) { //存在反向边,更新low[u] 77 | s.push(t); 78 | low[u] = min(low[u], pre[v]); 79 | } 80 | } 81 | if (fa == -1 && child == 1) iscut[u] = false; //根节点特判 82 | } 83 | 84 | void find_bcc() { 85 | bcnt = dfs_clock = 0; 86 | memset(pre, 0, sizeof(pre)); 87 | memset(bccno, 0, sizeof(bccno)); 88 | memset(iscut, 0, sizeof(iscut)); 89 | for (int i = 1; i <= n; i++) { 90 | if (!pre[i]) dfs(i, -1); 91 | } 92 | } 93 | 94 | /* 95 | Edge-Biconnected Component(可以处理重边) 96 | iscut[]为割边集 97 | bccno[]为双连通点集,保存为编号 98 | */ 99 | struct Edge { 100 | int u, v; 101 | } e[N * N]; 102 | bool iscut[N * N]; 103 | int first[N], Next[N * N], pre[N], low[N], bccno[N]; 104 | int n, m, mt, bcnt, dfs_clock; 105 | stack s; 106 | 107 | void dfs(int u, int fa) { 108 | pre[u] = low[u] = ++dfs_clock; 109 | s.push(u); 110 | int cnt = 0; 111 | for (int i = first[u]; i != -1; i = Next[i]) { 112 | int v = e[i].v; 113 | if (!pre[v]) { 114 | dfs(v, u); 115 | low[u] = min(low[u], low[v]); 116 | if (low[v] > pre[u]) iscut[i] = true; //存在割边 117 | } else if (fa == v) { //反向边更新 118 | if (cnt) low[u] = min(low[u], pre[v]); 119 | cnt++; 120 | } else 121 | low[u] = min(low[u], pre[v]); 122 | } 123 | if (low[u] == pre[u]) { //充分必要条件 124 | int x = -1; 125 | bcnt++; 126 | while (x != u) { 127 | x = s.top(); 128 | s.pop(); 129 | bccno[x] = bcnt; 130 | } 131 | } 132 | } 133 | 134 | void find_bcc() { 135 | bcnt = dfs_clock = 0; 136 | memset(pre, 0, sizeof(pre)); 137 | memset(bccno, 0, sizeof(bccno)); 138 | memset(iscut, 0, sizeof(iscut)); 139 | for (int i = 1; i <= n; i++) { 140 | if (!pre[i]) dfs(i, -1); 141 | } 142 | } 143 | 144 | /* 145 | Edge-Biconnected Component(不能处理重边) 146 | iscut[]为割边集 147 | bccno[]为双连通点集,保存为编号 148 | */ 149 | struct Edge { 150 | int u, v; 151 | } e[N * N]; 152 | bool iscut[N * N]; 153 | int first[N], Next[N * N], pre[N], low[N], bccno[N]; 154 | int n, m, mt, bcnt, dfs_clock; 155 | stack s; 156 | 157 | void addedge(int a, int b) { 158 | e[mt].u = a; 159 | e[mt].v = b; 160 | Next[mt] = first[a]; 161 | first[a] = mt++; 162 | e[mt].u = b; 163 | e[mt].v = a; 164 | Next[mt] = first[b]; 165 | first[b] = mt++; 166 | } 167 | 168 | void dfs(int u, int fa) { 169 | pre[u] = low[u] = ++dfs_clock; 170 | s.push(u); 171 | for (int i = first[u]; i != -1; i = Next[i]) { 172 | int v = e[i].v; 173 | if (!pre[v]) { 174 | dfs(v, u); 175 | low[u] = min(low[u], low[v]); 176 | if (low[v] > pre[u]) iscut[i] = true; //存在割边 177 | } else if (v != fa && pre[v] < pre[u]) { //反向边更新 178 | low[u] = min(low[u], pre[v]); 179 | } 180 | } 181 | if (low[u] == pre[u]) //充分必要条件 182 | { 183 | int x = -1; 184 | bcnt++; 185 | while (x != u) { 186 | x = s.top(); 187 | s.pop(); 188 | bccno[x] = bcnt; 189 | } 190 | } 191 | } 192 | 193 | void find_bcc() { 194 | bcnt = dfs_clock = 0; 195 | memset(pre, 0, sizeof(pre)); 196 | memset(bccno, 0, sizeof(bccno)); 197 | memset(iscut, 0, sizeof(iscut)); 198 | for (int i = 1; i <= n; i++) { 199 | if (!pre[i]) dfs(i, -1); 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /Graph-theory/Connectivity/BCC_edge(1).cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | const int N = 10005; 7 | const int M = 20005; 8 | 9 | struct Edge{ 10 | int u, v, id, next; 11 | bool iscut; 12 | Edge() {} 13 | Edge(int u, int v, int id, int next): u(u), v(v), id(id), next(next), iscut(false) {} 14 | }E[M * 2], cut[M]; 15 | 16 | int n, m, tot, bcc_cnt, dfs_clock, cut_cnt; 17 | int head[N], val[N], pre[N], lowlink[N], bccno[N]; 18 | 19 | void init() { 20 | memset(head, -1, sizeof(head)); 21 | tot = 0; 22 | } 23 | 24 | void AddEdge(int u, int v, int id) { 25 | E[tot] = Edge(u, v, id, head[u]); 26 | head[u] = tot++; 27 | E[tot] = Edge(v, u, id, head[v]); 28 | head[v] = tot++; 29 | } 30 | 31 | void dfs_cut(int u, int fa) { 32 | pre[u] = lowlink[u] = ++dfs_clock; 33 | for (int i = head[u]; ~i; i = E[i].next) { 34 | int v = E[i].v; 35 | if (E[i].id == fa) continue; 36 | if (!pre[v]) { 37 | dfs_cut(v, E[i].id); 38 | lowlink[u] = min(lowlink[u], lowlink[v]); 39 | if (lowlink[v] > pre[u]) { 40 | E[i].iscut = E[i^1].iscut = true;//标记割边 41 | cut[cut_cnt++] = E[i];//存放割边 42 | } 43 | } else lowlink[u] = min(lowlink[u], pre[v]); 44 | } 45 | } 46 | 47 | void find_cut() { 48 | dfs_clock = cut_cnt = 0; 49 | memset(pre, 0, sizeof(pre)); 50 | for (int i = 0; i < n; i++) 51 | if (!pre[i]) dfs_cut(i, -1); 52 | } 53 | 54 | void dfs_bcc(int u) { 55 | pre[u] = 1; 56 | bccno[u] = bcc_cnt; 57 | for (int i = head[u]; ~i; i = E[i].next) { 58 | if (E[i].iscut) continue; 59 | int v = E[i].v; 60 | if (pre[v]) continue; 61 | dfs_bcc(v); 62 | } 63 | } 64 | 65 | void find_bcc() { 66 | bcc_cnt = 0; 67 | memset(pre, 0, sizeof(pre)); 68 | for (int i = 0; i < n; i++) { 69 | if (!pre[i]) { 70 | dfs_bcc(i); 71 | bcc_cnt++; 72 | } 73 | } 74 | } 75 | 76 | int main() { 77 | return 0; 78 | } 79 | 80 | 81 | //-------------------------------------------------------------------------------- 82 | #include 83 | #include 84 | #include 85 | using namespace std; 86 | const int MAXNODE = 10005; 87 | const int MAXEDGE = 100010; 88 | const int INF = 0x3f3f3f3f; 89 | 90 | struct Edge{ 91 | int v, id, next; 92 | bool bridge; 93 | Edge() {} 94 | Edge(int v, int id, int next): v(v), id(id), next(next), bridge(false){} 95 | }E[MAXEDGE * 2], cut[MAXEDGE]; 96 | 97 | //pre纪录的是时间戳,lowlink纪录的是该点及其该子孙节点所能返回的最早时间戳是多少,bccno纪录的是该点当前是属于哪个bcc的 98 | int head[MAXNODE], pre[MAXNODE], lowlink[MAXNODE], bccno[MAXNODE], Stack[MAXNODE], belong[MAXNODE]; 99 | int n, m, tot, bcc_cnt, dfs_clock, top; 100 | 101 | void AddEdge(int u, int v, int id) { 102 | E[tot] = Edge(v, id, head[u]); 103 | head[u] = tot++; 104 | E[tot] = Edge(u, id, head[v]); 105 | head[v] = tot++; 106 | } 107 | 108 | void init() { 109 | memset(head, -1, sizeof(head)); 110 | tot = 0; 111 | } 112 | 113 | //边双连通 114 | void dfs(int u, int fa) { 115 | pre[u] = lowlink[u] = ++dfs_clock; 116 | Stack[++top] = u; 117 | 118 | for (int i = head[u]; ~i; i = E[i].next) { 119 | int v = E[i].v; 120 | if (!pre[v]) { 121 | dfs(v, u); 122 | lowlink[u] = min(lowlink[u], lowlink[v]); 123 | if (lowlink[v] > pre[u]) { 124 | E[i].bridge = E[i ^ 1].bridge = true; 125 | bcc_cnt++; 126 | while (1) { 127 | int x = Stack[top--]; 128 | belong[x] = bcc_cnt; 129 | if (x == v) break; 130 | } 131 | } 132 | } 133 | else if (pre[v] < pre[u] && v != fa) lowlink[u] = min(lowlink[u], pre[v]); 134 | } 135 | } 136 | 137 | void find_bcc() { 138 | memset(pre, 0, sizeof(pre)); 139 | memset(bccno, 0, sizeof(bccno)); 140 | dfs_clock = bcc_cnt = 0; 141 | for (int i = 0; i < n; i++) 142 | if (!pre[i]) dfs(i, -1); 143 | } 144 | 145 | int main() { 146 | init(); 147 | return 0; 148 | } -------------------------------------------------------------------------------- /Graph-theory/Connectivity/BCC_edge(2).cpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | BCC:BiConnected Component. 4 | 无向图的连通分量(BCC)模版. 5 | 边双连通:如果任意两点至少存在两条“边不重复“的路径,我们说这个图是边-双连通的,这个要求低一点,只需要每条边都至少在一个简单环中,即所有的边都不是桥. 6 | 7 | */ 8 | struct BccEdge { 9 | static const int MXN = 100005; 10 | struct Edge { int v,eid; }; 11 | int n,m,step,par[MXN],dfn[MXN],low[MXN]; 12 | vector E[MXN]; 13 | DisjointSet djs; 14 | void init(int _n) { 15 | n = _n; m = 0; 16 | for (int i=0; i E[MXN], ap; 11 | vector bcc[MXN]; 12 | int top; 13 | pii stk[MXN]; 14 | void init(int _n) { 15 | n = _n; 16 | nBcc = step = 0; 17 | for (int i=0; i= dfn[u]) { 33 | if(v != root) ap.PB(v); 34 | do { 35 | assert(top > 0); 36 | bcc[nBcc].PB(stk[--top]); 37 | } while (stk[top] != pii(u,v)); 38 | nBcc++; 39 | } 40 | low[u] = min(low[u], low[v]); 41 | } else { 42 | if (dfn[v] < dfn[u]) stk[top++] = pii(u,v); 43 | low[u] = min(low[u],dfn[v]); 44 | } 45 | } 46 | if (u == root && son > 1) ap.PB(u); 47 | } 48 | // return the edges of each bcc; 49 | vector> solve() { 50 | vector> res; 51 | for (int i=0; i 7 | #include 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | const int MAXNODE = 10005; 13 | const int MAXEDGE = 100010; 14 | const int INF = 0x3f3f3f3f; 15 | 16 | struct Edge{ 17 | int v, id, next; 18 | bool bridge; 19 | Edge() {} 20 | Edge(int v, int id, int next): v(v), id(id), next(next), bridge(false){} 21 | }E[MAXEDGE * 2], cut[MAXEDGE]; 22 | 23 | struct Node { 24 | int u, v; 25 | Node() {} 26 | Node(int u, int v): u(u), v(v) {} 27 | }; 28 | 29 | stack Stack; 30 | vector bcc[MAXNODE]; 31 | 32 | int head[MAXNODE], pre[MAXNODE], lowlink[MAXNODE], bccno[MAXNODE]; 33 | int n, m, tot, bcc_cnt, dfs_clock, cut_cnt; 34 | bool iscut[MAXNODE]; 35 | 36 | void AddEdge(int u, int v, int id) { 37 | E[tot] = Edge(v, id, head[u]); 38 | head[u] = tot++; 39 | E[tot] = Edge(u, id, head[v]); 40 | head[v] = tot++; 41 | } 42 | 43 | void init() { 44 | memset(head, -1, sizeof(head)); 45 | tot = 0; 46 | } 47 | 48 | void dfs(int u, int fa) { 49 | pre[u] = lowlink[u] = ++dfs_clock; 50 | int child = 0; 51 | for (int i = head[u]; ~i; i = E[i].next) { 52 | int v = E[i].v; 53 | if (!pre[v]) { 54 | Stack.push(Node(u, v)); 55 | child++; 56 | dfs(v, u); 57 | lowlink[u] = min(lowlink[u], lowlink[v]); 58 | if (lowlink[v] >= pre[u]) { 59 | if (lowlink[v] > pre[u]) { 60 | E[i].bridge = E[i ^ 1].bridge = true; 61 | cut[cut_cnt++] = E[i]; 62 | } 63 | iscut[u] = true; 64 | bcc_cnt++; bcc[bcc_cnt].clear(); 65 | while (1) { 66 | Node x = Stack.top(); Stack.pop(); 67 | if (bccno[x.u] != bcc_cnt) { 68 | bcc[bcc_cnt].push_back(x.u); 69 | bccno[x.u] = bcc_cnt; 70 | } 71 | if (bccno[x.v] != bcc_cnt) { 72 | bcc[bcc_cnt].push_back(x.v); 73 | bccno[x.v] = bcc_cnt; 74 | } 75 | if (x.u == u && x.v == v) break; 76 | } 77 | } 78 | } 79 | else if (v != fa && pre[v] < pre[u]) { 80 | Stack.push(Node(u, v)); 81 | lowlink[u] = min(lowlink[u], pre[v]); 82 | } 83 | } 84 | if (fa < 0 && child == 1) iscut[u] = 0; 85 | } 86 | 87 | void find_bcc() { 88 | memset(pre, 0, sizeof(pre)); 89 | memset(iscut, 0, sizeof(iscut)); 90 | memset(bccno, 0, sizeof(bccno)); 91 | dfs_clock = bcc_cnt = cut_cnt = 0; 92 | for (int i = 0; i < n; i++) 93 | if (!pre[i]) dfs(i, -1); 94 | } 95 | 96 | int main() { 97 | init(); 98 | return 0; 99 | } -------------------------------------------------------------------------------- /Graph-theory/Connectivity/Kosaraju.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: zhaoyang.liang 3 | * @Github: https://github.com/LzyRapx 4 | * @Date: 2019-06-13 00:02:05 5 | */ 6 | 7 | /* 8 | Kosaraju’s algorithm1---- 9 | is an efficient method for finding the strongly connected 10 | components of a directed graph. The algorithm performs two depth-first searches: 11 | the first search constructs a list of nodes according to the structure of the graph, 12 | and the second search forms the strongly connected components. 13 | */ 14 | 15 | /* 16 | The time complexity of the algorithm is O(n + m), because the algorithm performs two depth-first searches. 17 | */ 18 | #include 19 | using namespace std; 20 | #define PB push_back 21 | const int MXN = 1e6; 22 | 23 | // Scc: Strongly Connected Components 24 | 25 | struct Scc{ 26 | int n, nScc, vst[MXN], bln[MXN]; 27 | vector E[MXN], rE[MXN], vec; 28 | void init(int _n){ 29 | n = _n; 30 | for (int i=0; i> u >> v; 76 | addedge(u, v); 77 | } 78 | // std::cout << "/* message */" << '\n'; 79 | find_scc(); 80 | std::cout << scnt << '\n'; 81 | } 82 | 83 | /* 84 | 1 2 85 | 2 1 86 | 1 2 87 | 5 4 88 | 3 2 89 | 6 5 90 | 3 7 91 | 6 3 92 | 7 6 93 | 2 5 94 | 95 | answer: 96 | 4 97 | */ 98 | -------------------------------------------------------------------------------- /Graph-theory/Flows and cuts/Dinic(1).cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | #define SZ(x) ((int)(x).size()) 5 | #define PB push_back 6 | 7 | 8 | // O(n^2*m) 9 | 10 | struct Dinic{ 11 | static const int MXN = 10000; 12 | struct Edge{ int v,f,re; }; 13 | int n,s,t,level[MXN]; 14 | vector E[MXN]; 15 | void init(int _n, int _s, int _t){ 16 | n = _n; s = _s; t = _t; 17 | for (int i=0; i que; 26 | que.push(s); 27 | level[s] = 0; 28 | while (!que.empty()){ 29 | int u = que.front(); que.pop(); 30 | for (auto it : E[u]){ 31 | if (it.f > 0 && level[it.v] == -1){ 32 | level[it.v] = level[u]+1; 33 | que.push(it.v); 34 | } 35 | } 36 | } 37 | return level[t] != -1; 38 | } 39 | int DFS(int u, int nf){ 40 | if (u == t) return nf; 41 | int res = 0; 42 | for (auto &it : E[u]){ 43 | if (it.f > 0 && level[it.v] == level[u]+1){ 44 | int tf = DFS(it.v, min(nf,it.f)); 45 | res += tf; nf -= tf; it.f -= tf; 46 | E[it.v][it.re].f += tf; 47 | if (nf == 0) return res; 48 | } 49 | } 50 | if (!res) level[u] = -1; 51 | return res; 52 | } 53 | int flow(int res=0){ 54 | // std::cout << "flow" << '\n'; 55 | while ( BFS() ) 56 | res += DFS(s,2147483647); 57 | return res; 58 | } 59 | }flow; 60 | 61 | int main() 62 | { 63 | int n,m; 64 | std::cin >> n >> m; 65 | int s = 0 ,t= n-1; 66 | flow.init(n+1,s,t); 67 | for(int i=1;i<=m;i++) { 68 | int u,v,cap; 69 | std::cin >> u >> v >> cap; 70 | u--,v--; 71 | flow.add_edge(u,v,cap); 72 | } 73 | int ans = flow.flow(0); 74 | std::cout << ans << '\n'; 75 | return 0; 76 | } 77 | /* 78 | 6 8 79 | 1 2 5 80 | 1 4 4 81 | 2 3 6 82 | 4 5 1 83 | 3 6 5 84 | 5 6 2 85 | 4 2 3 86 | 3 5 8 87 | 88 | answer: 89 | 7 90 | */ 91 | -------------------------------------------------------------------------------- /Graph-theory/Flows and cuts/Dinic(2).cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | /* 4 | Dinic O(n^2*m) 5 | 如果所有容量均为1,复杂度O(min(n^(2/3) * m, m^(1/2)) * m) 6 | 对于二分图,复杂度O(n^(1/2) * m) 7 | 构造层次图,然后在层次图上DFS找增光路,路径 d[u]=d[v]+1 8 | 加当前弧优化,效率提高 9 | */ 10 | const int INF = 2147483647; 11 | const int N = 10000; 12 | struct Edge 13 | { 14 | int u,v,cap; 15 | }e[N*N]; 16 | 17 | int first[N],Next[N*N],d[N],cur[N]; 18 | int n,m,S,T,mt; 19 | 20 | void addedge(int a,int b,int val) 21 | { 22 | e[mt].u=a; 23 | e[mt].v=b; 24 | e[mt].cap=val; 25 | Next[mt]=first[a]; 26 | first[a]=mt++; 27 | 28 | e[mt].u=b; 29 | e[mt].v=a; 30 | e[mt].cap=0; 31 | Next[mt]=first[b]; 32 | first[b]=mt++; 33 | } 34 | 35 | int bfs() 36 | { 37 | //std::cout << "bfs" << '\n'; 38 | queue q; 39 | memset(d,0,sizeof(d)); 40 | q.push(S); 41 | d[S]=1; 42 | while(!q.empty()){ 43 | int u=q.front(); 44 | q.pop(); 45 | //这里为什么是i!=-1呢?因为,标号是从0开始的 46 | for(int i=first[u];i!=-1;i=Next[i]){ 47 | if(e[i].cap && !d[e[i].v]){ 48 | d[e[i].v]=d[u]+1; 49 | q.push(e[i].v); 50 | } 51 | } 52 | } 53 | return d[T]; 54 | } 55 | 56 | int dfs(int u,int a) 57 | { 58 | if(u==T || a==0) return a;// a 为瓶颈。 59 | int f = 0,flow=0; 60 | for(int& i=cur[u];i!=-1;i=Next[i]){ //当前弧优化,从上次的弧考虑 61 | if( d[u]+1==d[e[i].v] && (f=dfs(e[i].v,min(a,e[i].cap)) )){ 62 | e[i].cap-=f; 63 | //这里的^是很常用的,因为前向星加边是两条一起加的,只是反向边一开始是为零的, 64 | //所以^1一下可以得到另一条边,比如0^1 = 1,1 ^ 1 = 0, 2^1 = 3,3 ^1 = 2; 65 | e[i^1].cap+=f; 66 | flow+=f; 67 | a-=f; 68 | if(!a)break; 69 | } 70 | } 71 | return flow; 72 | } 73 | 74 | int dinic() 75 | { 76 | //std::cout << "dinic" << '\n'; 77 | int flow=0; 78 | while(bfs()){ 79 | for(int i=0;i<=n;i++)cur[i]=first[i]; //注意这里是所有点都要赋值!!! 80 | flow+=dfs(S,INF); 81 | } 82 | return flow; 83 | } 84 | 85 | int main() 86 | { 87 | memset(cur,-1,sizeof(cur)); 88 | memset(first,-1,sizeof(first)); 89 | 90 | std::cin >> n >> m; 91 | S = 1, T = n; 92 | for(int i=1;i<=m;i++) { 93 | int u,v,cap; 94 | std::cin >> u >> v >> cap; 95 | addedge(u,v,cap); 96 | } 97 | std::cout << dinic() << '\n'; 98 | return 0; 99 | } 100 | /* 101 | 6 8 102 | 1 2 5 103 | 1 4 4 104 | 2 3 6 105 | 4 5 1 106 | 3 6 5 107 | 5 6 2 108 | 4 2 3 109 | 3 5 8 110 | 111 | answer: 112 | 7 113 | */ 114 | -------------------------------------------------------------------------------- /Graph-theory/Flows and cuts/Edmonds–Karp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | /* 5 | The Edmonds–Karp algorithm chooses each path so that the number 6 | of edges on the path is as small as possible. This can be done by using breadth- 7 | first search instead of depth-first search for finding paths. It can be proven that 8 | this guarantees that the flow increases quickly, and the time complexity of the 9 | algorithm is O(n*m^2). 10 | 11 | time complexity is O(VE^2). 12 | */ 13 | #define maxn 10010 14 | int maxData = 0x7fffffff; 15 | int capacity[maxn][maxn]; //记录残留网络的容量 16 | int flow[maxn]; //标记从源点到当前节点实际还剩多少流量可用 17 | int pre[maxn]; //标记在这条路径上当前节点的前驱,同时标记该节点是否在队列中 18 | int n,m; 19 | queue que; 20 | 21 | int BFS(int src,int des) 22 | { 23 | 24 | while(!que.empty()) que.pop(); //队列清空 25 | 26 | for(int i=1;i0 && pre[i]==-1) 42 | { 43 | pre[i] = index; //记录前驱 44 | flow[i] = min(capacity[index][i],flow[index]); //关键:迭代的找到增量 45 | que.push(i); 46 | } 47 | } 48 | } 49 | //如果n点找不到增广路,说明已经没增广路到汇点了 50 | if(pre[des]==-1) //残留图中不再存在增广路径 51 | return -1; 52 | else 53 | return flow[des]; 54 | } 55 | 56 | int maxFlow(int src,int des) 57 | { 58 | int increasement= 0; 59 | int sumflow = 0; 60 | //不断通过bfs来找增广路,然后sumflow+=增广路上的流量。 61 | while((increasement=BFS(src,des))!=-1) 62 | { 63 | int k = des; //利用前驱寻找路径 64 | while(k!=src)//不断调整流量大小。 65 | { 66 | int last = pre[k]; 67 | capacity[last][k] -= increasement; //改变正向边的容量 68 | capacity[k][last] += increasement; //改变反向边的容量 69 | k = last; 70 | } 71 | sumflow += increasement; 72 | } 73 | return sumflow; 74 | } 75 | 76 | int main() 77 | { 78 | int S,T; 79 | int start,end,cap; 80 | while(cin>>n>>m>>S>>T) 81 | { 82 | memset(capacity,0,sizeof(capacity)); 83 | memset(flow,0,sizeof(flow)); 84 | for(int i=0;i>start>>end>>cap; 87 | if(start == end) continue; //考虑起点终点相同的情况 88 | capacity[start][end] +=cap; //此处注意可能出现多条同一起点终点的情况 89 | } 90 | cout< 2 | using namespace std; 3 | 4 | 5 | /* 6 | The Ford–Fulkerson algorithm can finds the maximum flow in a graph. The 7 | algorithm begins with an empty flow, and at each step finds a path from the 8 | source to the sink that generates more flow. Finally, when the algorithm cannot 9 | increase the flow anymore, the maximum flow has been found. 10 | 11 | O(VE^2) = O(Km) 12 | */ 13 | const int maxn= 250; 14 | const int inf=INT_MAX; 15 | 16 | struct edge 17 | { 18 | int to,cap,rev; 19 | }; 20 | 21 | vector G[maxn]; 22 | 23 | bool used[maxn]; 24 | 25 | void addedge(int from ,int to,int cap) 26 | { 27 | G[from].push_back((edge){to,cap,(int)G[to].size()}); 28 | G[to].push_back((edge){from,0,(int)G[from].size()-1}); 29 | } 30 | 31 | int dfs(int v,int t,int f) 32 | { 33 | if(v==t) return f; 34 | used[v]=true; 35 | for(int i=0;i0) 39 | { 40 | int d=dfs(e.to,t,min(f,e.cap)); 41 | if(d>0) 42 | { 43 | e.cap-=d; 44 | G[e.to][e.rev].cap+=d; 45 | return d; 46 | } 47 | } 48 | } 49 | return 0; 50 | } 51 | 52 | int max_flow(int s,int t) 53 | { 54 | int flow=0; 55 | while(true) 56 | { 57 | memset(used,false,sizeof(used)); 58 | int f=dfs(s,t,inf); //不断找从s到t的增广路 59 | if(f==0) return flow; //找不到了就回去 60 | flow += f; //找到一个流量f的路 61 | } 62 | } 63 | 64 | void init(int m) 65 | { 66 | for(int i=0;i>n>>m) 76 | { 77 | init(m); 78 | for(int i=0;i>u>>v>>cap; 82 | addedge(u,v,cap); 83 | } 84 | cout< que; 32 | bool spfa() { 33 | memset(vis, 0, sizeof(vis)); 34 | memset(dis, 0x7f, sizeof(dis)); 35 | dis[st] = 0; 36 | que.push(st); 37 | while(!que.empty()) { 38 | int u = que.front(); que.pop(); 39 | vis[u] = false; 40 | for(int p = head[u]; ~p; p = next[p]) { 41 | int &v = to[p]; 42 | if(flow[p] && dis[v] > dis[u] + cost[p]) { 43 | dis[v] = dis[u] + cost[p]; 44 | pre[v] = p; 45 | if(!vis[v]) { 46 | que.push(v); 47 | vis[v] = true; 48 | } 49 | } 50 | } 51 | } 52 | return dis[ed] < INF; 53 | } 54 | 55 | int maxFlow, minCost; 56 | pairmin_cost_flow(int source, int sink) { 57 | st = source, ed = sink; 58 | maxFlow = minCost = 0; 59 | while(spfa()) { 60 | int u = ed, tmp = INF; 61 | while(u != st) { 62 | tmp = min(tmp, flow[pre[u]]); 63 | u = to[pre[u] ^ 1]; 64 | } 65 | u = ed; 66 | while(u != st) { 67 | flow[pre[u]] -= tmp; 68 | flow[pre[u] ^ 1] += tmp; 69 | u = to[pre[u] ^ 1]; 70 | } 71 | maxFlow += tmp; 72 | minCost += tmp * dis[ed]; 73 | } 74 | return {maxFlow,minCost}; 75 | } 76 | } flow; 77 | -------------------------------------------------------------------------------- /Graph-theory/Flows and cuts/edge-disjoint-path(1).cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzyrapx/Algorithmic_Template/6000f22159c74773ee3a9be329b17f7cf278494b/Graph-theory/Flows and cuts/edge-disjoint-path(1).cpp -------------------------------------------------------------------------------- /Graph-theory/Flows and cuts/edge-disjoint-path(2).cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Time Complexity: O(E*(V^3)) 3 | [For BFS it is O(V^2), if adjacency list representation is used, 4 | then Time Complexity would be O(E*(V^2))] 5 | */ 6 | 7 | #include 8 | 9 | using namespace std; 10 | 11 | // http://www.geeksforgeeks.org/find-edge-disjoint-paths-two-vertices/ 12 | // C++ program to find maximum number of edge disjoint paths 13 | 14 | bool BFS (vector< vector > &resiGraph, int src, int sink, int parent[]) { 15 | int V = resiGraph.size(); 16 | bool visited[V]; 17 | for (int i = 0; i < V; i++) { 18 | visited[i] = false; 19 | } 20 | queue q; 21 | q.push(src); 22 | visited[src] = true; 23 | parent[src] = -1; 24 | while (!q.empty()) { 25 | int u = q.front(); 26 | q.pop(); 27 | for (int v = 0; v < V; v++) { 28 | if ((!visited[v]) && (resiGraph[u][v] > 0)) { 29 | q.push (v); 30 | visited[v] = true; 31 | parent[v] = u; 32 | } 33 | } 34 | } 35 | return (visited[sink] == true); 36 | } 37 | 38 | //Ford–Fulkerson 39 | int findDisjointPaths(vector< vector > &graph, int src, int sink) { 40 | int V = graph.size(); 41 | vector< vector > resiGraph; 42 | for (int i = 0; i < V; i++) { 43 | vector temp; 44 | for (int j = 0; j < V; j++) { 45 | temp.push_back(graph[i][j]); 46 | } 47 | resiGraph.push_back(temp); 48 | temp.erase(temp.begin(), temp.end()); 49 | } 50 | int *parent = new int[V]; 51 | int max_flow = 0; 52 | while (BFS (resiGraph, src, sink, parent)) { 53 | int path_flow = INT_MAX; 54 | for (int v = sink; v != src; v = parent[v]) { 55 | int u = parent[v]; 56 | path_flow = min (path_flow, resiGraph[u][v]); 57 | } 58 | for (int v = sink; v != src; v = parent[v]) { 59 | int u = parent[v]; 60 | resiGraph[u][v] -= path_flow; 61 | resiGraph[v][u] += path_flow; 62 | } 63 | max_flow += path_flow; 64 | } 65 | return max_flow; 66 | } 67 | /* 68 | 0 1 1 1 0 0 0 0 69 | 0 0 1 0 0 1 0 0 70 | 0 0 0 1 0 0 1 0 71 | 0 0 0 0 0 0 0 0 72 | 0 0 1 0 0 0 0 1 73 | 0 1 0 0 0 0 0 1 74 | 0 0 0 0 0 1 0 1 75 | 0 0 0 0 0 0 0 0 76 | 77 | answer: 78 | 2 79 | */ 80 | int main () { 81 | 82 | vector< vector > graph(8,std::vector(8,0)); 83 | 84 | for(int i=0;i<8;i++) { 85 | for(int j=0;j<8;j++) { 86 | std::cin >> graph[i][j]; 87 | } 88 | } 89 | int src = 0; 90 | int sink = 7; 91 | cout << "There can be Maximum " << findDisjointPaths(graph, src, sink); 92 | cout << " Edge-Disjoint Paths from " << src << " to " << sink << " in the given graph." << endl; 93 | return 0; 94 | } 95 | -------------------------------------------------------------------------------- /Graph-theory/Flows and cuts/maximum_flow_goldberg_tarjan.cpp: -------------------------------------------------------------------------------- 1 | //http://codeforces.com/blog/entry/14378 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | #define fst first 8 | #define snd second 9 | #define all(c) ((c).begin()), ((c).end()) 10 | 11 | const long long INF = (1ll << 50); 12 | struct graph { 13 | typedef long long flow_type; 14 | struct edge { 15 | int src, dst; 16 | flow_type capacity, flow; 17 | size_t rev; 18 | }; 19 | int n; 20 | vector> adj; 21 | graph(int n) : n(n), adj(n) { } 22 | 23 | void add_edge(int src, int dst, int capacity) { 24 | adj[src].push_back({src, dst, capacity, 0, adj[dst].size()}); 25 | adj[dst].push_back({dst, src, 0, 0, adj[src].size() - 1}); 26 | } 27 | 28 | flow_type max_flow(int s, int t) { 29 | vector excess(n); 30 | vector dist(n), active(n), count(2*n); 31 | queue Q; 32 | auto enqueue = [&](int v) { 33 | if (!active[v] && excess[v] > 0) { active[v] = true; Q.push(v); } 34 | }; 35 | auto push = [&](edge &e) { 36 | flow_type f = min(excess[e.src], e.capacity - e.flow); 37 | if (dist[e.src] <= dist[e.dst] || f == 0) return; 38 | e.flow += f; 39 | adj[e.dst][e.rev].flow -= f; 40 | excess[e.dst] += f; 41 | excess[e.src] -= f; 42 | enqueue(e.dst); 43 | }; 44 | 45 | dist[s] = n; active[s] = active[t] = true; 46 | count[0] = n-1; count[n] = 1; 47 | for (int u = 0; u < n; ++u) 48 | for (auto &e: adj[u]) e.flow = 0; 49 | for (auto &e: adj[s]) { 50 | excess[s] += e.capacity; 51 | push(e); 52 | } 53 | while (!Q.empty()) { 54 | int u = Q.front(); Q.pop(); 55 | active[u] = false; 56 | 57 | for (auto &e: adj[u]) push(e); 58 | if (excess[u] > 0) { 59 | if (count[dist[u]] == 1) { 60 | int k = dist[u]; // Gap Heuristics 61 | for (int v = 0; v < n; v++) { 62 | if (dist[v] < k) continue; 63 | count[dist[v]]--; 64 | dist[v] = max(dist[v], n+1); 65 | count[dist[v]]++; 66 | enqueue(v); 67 | } 68 | } else { 69 | count[dist[u]]--; // Relabel 70 | dist[u] = 2*n; 71 | for (auto &e: adj[u]) 72 | if (e.capacity > e.flow) 73 | dist[u] = min(dist[u], dist[e.dst] + 1); 74 | count[dist[u]]++; 75 | enqueue(u); 76 | } 77 | } 78 | } 79 | 80 | flow_type flow = 0; 81 | for (auto e: adj[s]) flow += e.flow; 82 | return flow; 83 | } 84 | }; 85 | int read(){ int v = 0, f = 1;char c =getchar(); 86 | while( c < 48 || 57 < c ){if(c=='-') f = -1;c = getchar();} 87 | while(48 <= c && c <= 57) v = v*10+c-48, c = getchar(); 88 | return v*f;} 89 | int main() { 90 | 91 | int n,m,s,t; 92 | // scanf("%d%d%d%d", &n, &m,&s,&t); 93 | n=read(),m=read(),s=read(),t=read(); 94 | graph g(n); 95 | for (int i = 0; i < m; ++i) { 96 | int u, v, w; 97 | //scanf("%d %d %d", &u, &v, &w); 98 | u=read(),v=read(),w=read(); 99 | u--,v--; 100 | g.add_edge(u, v, w); 101 | } 102 | printf("%d\n", g.max_flow(s-1, t-1)); 103 | return 0; 104 | } -------------------------------------------------------------------------------- /Graph-theory/Matching/Kuhn-Munkras (KM).cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | #include 5 | using namespace std; // NOLINT 6 | const int INF = 0x3f3f3f3f; 7 | 8 | // O(n^3) 9 | 10 | // return largest macthing.(A interger) 11 | template 12 | T KM(vector>& mp) 13 | { 14 | int n = mp.size(); // left num 15 | int m = mp[0].size(); // right num 16 | static vector rlink; //, llink; // right link to left, left link to right 17 | //llink.resize(n), fill(llink.begin(), llink.end(), -1); 18 | rlink.resize(m); 19 | fill(rlink.begin(), rlink.end(), -1); 20 | vector fl, fr; // flag num 21 | fl.resize(n); 22 | fill(fl.begin(), fl.end(), -INF); 23 | fr.resize(m); 24 | fill(fr.begin(), fr.end(), 0); 25 | for (int i = 0; i < n; i++) { 26 | for (int j = 0; j < m; j++) { 27 | fl[i] = max(fl[i], mp[i][j]); 28 | } 29 | } 30 | static vector slack; 31 | slack.resize(m); 32 | static vector lused, rused; // record used point in a dfs 33 | lused.resize(n), rused.resize(m); 34 | static function dfs = [&](int k) { // find a method that can make k link to right 35 | lused[k] = 1; 36 | for (int i = 0; i < m; i++) { 37 | if (mp[k][i] == -INF || rused[i]) continue; 38 | T tmp = fl[k] + fr[i] - mp[k][i]; 39 | if (!tmp) { 40 | rused[i] = 1; 41 | if (rlink[i] == -1 || dfs(rlink[i])) { 42 | rlink[i] = k; // make or change link 43 | // llink[k] = i; 44 | return true; 45 | } 46 | } else slack[i] = min(slack[i], tmp); 47 | } 48 | return false; 49 | }; 50 | for (int d = 0; d < n; d++) { 51 | fill(slack.begin(), slack.end(), INF); 52 | while (1) { 53 | fill(lused.begin(), lused.end(), 0); 54 | fill(rused.begin(), rused.end(), 0); 55 | if (dfs(d)) break; 56 | T e = INF; 57 | for (int i = 0; i < m; i++) { // min slack 58 | if (!rused[i]) e = min(e, slack[i]); 59 | } 60 | if (e == INF) return -1; 61 | for (int i = 0; i < n; i++) { 62 | if (lused[i]) fl[i] -= e; 63 | } 64 | for (int i = 0; i < m; i++) { 65 | if (rused[i]) fr[i] += e; 66 | else if (mp[d][i] != -INF) slack[i] -= e; 67 | } 68 | } 69 | } 70 | T res = 0; 71 | for (int i = 0; i < n; i++) { 72 | res += mp[rlink[i]][i]; 73 | } 74 | return res; 75 | } 76 | int n; 77 | int main(int argc, char const *argv[]) { 78 | 79 | std::cin >> n; 80 | std::vector> mp(n+1,std::vector(n+1,0)); 81 | for(int i=0;i<6;i++) { 82 | int u,v; 83 | std::cin >> u >> v; 84 | u--;v--; 85 | mp[u][v] = 1; 86 | } 87 | 88 | std::cout << KM(mp) << '\n'; 89 | return 0; 90 | } 91 | /* 92 | 8 93 | 1 5 94 | 2 7 95 | 3 8 96 | 3 6 97 | 3 5 98 | 4 6 99 | 100 | answer: 101 | 4 102 | */ 103 | -------------------------------------------------------------------------------- /Graph-theory/Matching/匈牙利算法 O(n^3).cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 匈牙利算法 3 | 最小点集覆盖 = 最大匹配数 4 | 最小路径覆盖 = n - 最大匹配数 5 | 最大独立集 = n - 最大匹配数 6 | */ 7 | 8 | /* 邻接矩阵 O(n^3) */ 9 | // TLE版本 10 | 11 | int vis[maxn]; 12 | int y[maxn]; 13 | int g[maxn][maxn]; 14 | int n; // 点数 15 | 16 | int dfs(int u) 17 | { 18 | for(int v = 0; v < n ; v++) { 19 | if(g[u][v] && vis[v] == 0) { 20 | vis[v] = 1; 21 | if(y[v] == -1 || dfs(y[v])) { 22 | y[v] = u; 23 | return 1; 24 | } 25 | } 26 | } 27 | return 0; 28 | } 29 | int match() //返回匹配的点数,所以一定是偶数 30 | { 31 | int cnt = 0; 32 | memset(y,-1,sizeof(y)); 33 | for(int i = 0; i < n; i++) { 34 | memset(vis,0,sizeof(vis)); 35 | if(dfs(i)) { 36 | cnt++; 37 | } 38 | } 39 | return cnt; 40 | } 41 | -------------------------------------------------------------------------------- /Graph-theory/Matching/匈牙利算法 O(nm).cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzyrapx/Algorithmic_Template/6000f22159c74773ee3a9be329b17f7cf278494b/Graph-theory/Matching/匈牙利算法 O(nm).cpp -------------------------------------------------------------------------------- /Graph-theory/Shortest-path/Bellman-Ford.cpp: -------------------------------------------------------------------------------- 1 | 2 | // 对于单源最短路径的问题,Dijkstra算法对于带负权边的图就无能为力了,而Bellman-Ford算法就可以解决这个问题。 3 | // Bellman-Ford算法:可以处理带负权边的图。 4 | // 算法的实现模板:O(n*m) 5 | 6 | typedef struct edge 7 | { 8 | int v; //起点 9 | int u; //终点 10 | int w; 11 | }edge; 12 | edge edges[20004]; 13 | int dis[1004]; 14 | int maxData=1000000000; //此处特别注意,Bellman-Ford算法中不要使用0x7fffffff 15 | int edgenum; 16 | 17 | //n:点 ,m:边 18 | /* 19 | (负权环)A negative cycle can be detected using the Bellman–Ford algorithm by running 20 | the algorithm for n rounds. If the last round reduces any distance, the graph 21 | contains a negative cycle. 22 | */ 23 | bool BellmanFord(int s) 24 | { 25 | bool flag=false; 26 | for(int i=1;idis[edges[j].v]+edges[j].w); 38 | { 39 | flag=true; 40 | dis[edges[j].u]=dis[edges[j].v]+edges[j].w 41 | } 42 | } 43 | if(!flag) break; 44 | } 45 | 46 | for(int i=0;i dis[edges[i].v]+edges[i].w) 49 | { 50 | return false; 51 | } 52 | } 53 | return true; 54 | } 55 | 56 | //主函数中: 57 | edgenum=0; 58 | for(i=0;i>start>>end>>w; 61 | edges[edgenum].v=start; 62 | edges[edgenum].u=end; 63 | edges[edgenum].w=w; 64 | edgenum++; 65 | } 66 | 67 | //简易版: 68 | 69 | // std::vector> edge; // make_tuple(s,e,w); 70 | 71 | // for (int i = 1; i <= n; i++) distance[i] = INF; 72 | // distance[x] = 0; 73 | // for (int i = 1; i <= n-1; i++) { 74 | // for (auto e : edges) { 75 | // int a, b, w; 76 | // tie(a, b, w) = e; 77 | // distance[b] = min(distance[b], distance[a]+w); 78 | // } 79 | // } 80 | -------------------------------------------------------------------------------- /Graph-theory/Shortest-path/Dijkstra(1).cpp: -------------------------------------------------------------------------------- 1 | 2 | // 带权有向图,求源到其他所有各顶点的最短路径长度。 3 | // 单源最短路径问题,但不能处理带负权边的图 4 | // 最短路:dijkstra算法 5 | 6 | /* 7 | The time complexity of the implementation is O(n+mlogm), because 8 | the algorithm goes through all nodes of the graph and adds for each edge at most 9 | one distance to the priority queue. 10 | */ 11 | 12 | // 算法的实现模板: 13 | #define MaxN 10010 //MaxN是点的个数 14 | #define MaxInt 200000000 //MabInt表示不可达 15 | int map[MaxN][MaxN],dist[MaxN]; 16 | bool mark[MaxN]; 17 | int start,end; 18 | 19 | int dijlstra() 20 | { 21 | for(int i=1;i<=end;i++) dist[i]=MaxInt; 22 | memset(mark,0,sizeof(mark)); 23 | dist[start]=0; 24 | //把起点并入集合,搜索的就可以从起点寻找第一条最短的边了 25 | for(int i=1;i<=end-1;i++) 26 | { 27 | min1=MaxInt; 28 | for(int j=1;j<=end;j++) //查找到原集合的最短的边 29 | { 30 | if(!mark[j] && dist[j]0) 41 | { 42 | temp=dist[minj]+map[minj][j]; 43 | if(temp 2 | using namespace std; 3 | /* 4 | dijkstra基本思想是采用贪心法,对于每个节点v[i],维护估计最短路长度最大值,每次取出一个使得该估计值最小的t, 5 | 并采用与t相连的边对其余点的估计值进行更新,更新后不再考虑t。 6 | 在此过程中,估计值单调递减,所以可以得到确切的最短路。 7 | */ 8 | /* 9 | The time complexity of the implementation is O(n+mlogm), because 10 | the algorithm goes through all nodes of the graph and adds for each edge at most 11 | one distance to the priority queue. 12 | */ 13 | #define INF 0x7fffffff 14 | const int max_v = 100010; 15 | typedef long long ll; 16 | typedef pair P; //first 最短距离 second 顶点编号 17 | struct edge { 18 | int to, cost; 19 | }; 20 | vector G[max_v]; 21 | int d[max_v]; 22 | bool used[max_v]; 23 | int V; 24 | void dijkstra(int s) 25 | { 26 | priority_queue, greater

> que; //从小到大按first排序 27 | for(int j = 0; j < max_v; j++) d[j] = INF; 28 | d[s] = 0; 29 | que.push(P(0, s)); 30 | while(!que.empty()) 31 | { 32 | P p = que.top(); 33 | que.pop(); 34 | int v = p.second; 35 | if(d[v] < p.first) continue; 36 | for(int i = 0; i < G[v].size(); i++) 37 | { 38 | edge e = G[v][i]; 39 | if(d[e.to] > d[v] + e.cost) 40 | { 41 | d[e.to] = d[v] + e.cost; 42 | que.push(P(d[e.to], e.to)); 43 | } 44 | } 45 | } 46 | } 47 | int n, m, s, t, u, v, w; 48 | int main(int argc, char *argv[]) 49 | { 50 | scanf("%d%d%d%d", &n, &m, &s, &t); 51 | for(int i = 0; i < m; i++) { 52 | scanf("%d%d%d", &u, &v, &w); 53 | G[u].push_back({v, w}); 54 | G[v].push_back({u, w}); 55 | } 56 | dijkstra(s); 57 | printf("%d\n", d[t]); 58 | return 0; 59 | } -------------------------------------------------------------------------------- /Graph-theory/Shortest-path/Dijkstra(求最短路和次短路以及其路径数).cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Dijkstra O(E * log V) 3 | p[]为路径 4 | 不能处理负权图 5 | */ 6 | 7 | struct Edge{ 8 | int u,v,w; 9 | }e[2*N]; 10 | int first[N],next[2*N],p[N],d[N]; 11 | int S,T,n,m,mt; 12 | 13 | void addedge(int a,int b,int c) 14 | { 15 | e[mt].u=a,e[mt].v=b;e[mt].w=c; 16 | next[mt]=first[a],first[a]=mt++; 17 | e[mt].u=b,e[mt].v=a;e[mt].w=c; 18 | next[mt]=first[b],first[b]=mt++; 19 | } 20 | 21 | int dijkstra(int s) //s is start 22 | { 23 | pii t; 24 | priority_queue,greater > q; 25 | memset(d,INF,sizeof(d)); 26 | d[s]=0; 27 | q.push(make_pair(d[s],s)); 28 | while(!q.empty()){ 29 | t=q.top();q.pop(); 30 | int u=t.second; 31 | if(t.first!=d[u])continue; 32 | for(int i=first[u];i!=-1;i=next[i]){ 33 | if(d[u]+e[i].woth.d; 63 | } 64 | }; 65 | struct Edge{ 66 | int u,v,w; 67 | }e[N*N]; 68 | int first[N],next[N*N],d[N][2],cnt[N][2]; 69 | int s,T,n,m,mt; 70 | 71 | void addedge(int a,int b,int c) 72 | { 73 | e[mt].u=a,e[mt].v=b;e[mt].w=c; 74 | next[mt]=first[a],first[a]=mt++; 75 | } 76 | 77 | int dijkstra(int s) 78 | { 79 | int u,v,w,k,dis; 80 | Node t; 81 | priority_queue q; 82 | memset(d,0x3f,sizeof(d)); 83 | d[s][0]=d[s][1]=0; 84 | cnt[s][0]=cnt[s][1]=1; 85 | t.d=0; 86 | t.u=s; 87 | t.flag=0; 88 | q.push(t); 89 | while(!q.empty()) 90 | { 91 | t=q.top();q.pop(); 92 | u=t.u; 93 | dis=t.d; 94 | k=t.flag; 95 | if(dis!=d[u][k])continue; 96 | for(int i=first[u];i!=-1;i=next[i]) 97 | { 98 | v=e[i].v; 99 | w=e[i].w; 100 | if(dis+w edge1,edge2; 18 | vector G1[N],G2[N]; 19 | 20 | struct cmp1{ 21 | bool operator()(const Node &a,const Node &b){ 22 | return a.d>b.d; 23 | } 24 | }; 25 | struct cmp2{ 26 | bool operator()(const Node &a,const Node &b){ 27 | return a.d+d[a.u]>b.d+d[a.u]; 28 | } 29 | }; 30 | 31 | void init(int n) 32 | { 33 | edge1.clear(); 34 | edge2.clear(); 35 | for(int i=1;i<=n;i++) G1[i].clear(); 36 | for(int i=1;i<=n;i++) G2[i].clear(); 37 | } 38 | 39 | void dijkstra(int s,vector& edge) { 40 | priority_queue,cmp1> q; 41 | for(int i=1;i<=n;i++)d[i]=INF; 42 | d[s]=0; 43 | memset(vis,0,sizeof(vis)); 44 | q.push((Node){0,s}); 45 | while(!q.empty()){ 46 | int u=q.top().u;q.pop(); 47 | if(vis[u])continue; 48 | vis[u]=1; 49 | for(int i=0;i<(int)G2[u].size();i++){ 50 | Edge& e=edge[G2[u][i]]; 51 | if(d[u]+e.dis& edge) { 60 | int cou[MAX]; 61 | memset(cou,0,sizeof(cou)); 62 | Node nod; 63 | priority_queue,cmp2> q; 64 | q.push((Node){d[s],s}); 65 | if(s==t)k++; 66 | while(1){ 67 | nod=q.top();q.pop(); 68 | if(nod.u==t) cou[nod.u]++; 69 | if(cou[nod.u]==k) return nod.d; 70 | for(int i=0;i q; 26 | memset(dis,INF,sizoeof(dis)); 27 | memset(cnt,0,sizeof(cnt)); 28 | q.push(s); 29 | dis[s]=0; 30 | cnt[s]=1; 31 | while(!q.empty()) 32 | { 33 | int u=q.front();q.pop(); 34 | inq[u]=0; 35 | for(int i=first[u];i!=-1;i=next[i]) 36 | { 37 | int v = e[i].v; 38 | int t = dis[u] + e[i].w; 39 | if(t < dis[v]) 40 | { 41 | dis[v]=t; 42 | if(!inq[v]) 43 | { 44 | if(++cnt[v]>=n) return 1; //存在负权环 45 | inq[v]=1; 46 | q.push(v); 47 | } 48 | } 49 | } 50 | } 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /Graph-theory/Shortest-path/SPFA(2).cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | struct point { 4 | int v,next,cap; 5 | } edge[20010*10]; 6 | 7 | int head[20010]; 8 | int dis[20010]; 9 | bool vis[20010]; 10 | int len, n, m; 11 | 12 | void addedge(int from, int to, int cap) 13 | { 14 | edge[len].v = to; 15 | edge[len].cap = cap; 16 | edge[len].next = head[from]; 17 | head[from] = len++; 18 | } 19 | 20 | void spfa(int start) 21 | { 22 | queueq; 23 | for(int i = 1; i <= n; i++){ 24 | dis[i] = 999999999; 25 | vis[i] = 0; 26 | } 27 | q.push(start); 28 | dis[start] = 0; 29 | vis[start] = 1; 30 | while(!q.empty()) 31 | { 32 | int x = q.front(); 33 | q.pop(); 34 | vis[x] = 0; 35 | for(int i = head[x]; i != -1; i = edge[i].next) 36 | { 37 | int v = edge[i].v; 38 | if(dis[v] > dis[x] + edge[i].cap){ 39 | dis[v] = dis[x] + edge[i].cap; 40 | if(!vis[v]){ 41 | vis[v] = 1; 42 | q.push(v); 43 | } 44 | } 45 | } 46 | } 47 | } 48 | int main() 49 | { 50 | int s,t; 51 | len = 0; 52 | int u,v,w; 53 | scanf("%d%d%d%d",&n,&m,&s,&t);//s到t的最短路 54 | memset(head,-1,sizeof(head)); 55 | for(int i=1;i<=m;i++){ 56 | cin>>u>>v>>w; 57 | addedge(u,v,w); 58 | addedge(v,u,w); 59 | } 60 | spfa(s); 61 | // cout<<"finish"<yk-xk 11 | 要满足第一个条件,Q必须属于集合{Pk+1, Pk+2, …, Pn},即Q必然在T中。 12 | 要满足第二个条件,Q在T中的第一关键字必须大于yk-xk(定值)。 13 | 因为我们要使得|PkQ|最小,所以我们实际上就是:从T的第一关键字大于某常数的所有元素中,寻找第二关键字最小的元素。 14 | 很明显,T可以用平衡二叉树来实现。按照第一关键字有序来建立平衡树,对于平衡树每个节点都记录以其为根的子树中第二关 15 | 键字最小的是哪个元素。查询、插入的时间复杂度都是O(logn)。 16 | 平衡二叉树也可以用线段树代替。 17 | 这里的代码用的BIT维护! 18 | 坐标变化: 19 | R1->R2:关于y=x对称,swap(x,y) 20 | R2->R3:考虑到代码的方便性,我们考虑R2->R7,x=-x。 21 | R7->R4:因为上面求的是R2->R7,因此这里还是关于y=x对称。 22 | */ 23 | 24 | 25 | const int INF=0x3f3f3f3f; 26 | 27 | struct Point{ 28 | int x,y,id; 29 | bool operator<(const Point p)const{ 30 | return x!=p.x?x=1;i-=lowbit(i)){ 72 | if(val=0;i--){ 118 | pos=lower_bound(hs,hs+m,T[i])-hs+1; //BIT中从1开始' 119 | w=query(pos,m); 120 | if(w!=-1) { 121 | addedge(p[i].id,p[w].id,dist(i,w)); 122 | } 123 | update(pos,p[i].x+p[i].y,i); 124 | } 125 | } 126 | //Kruskal - 找到第K小的边 127 | sort(e,e+mt); 128 | for(int i=0;i 12 | #include 13 | #include 14 | #include 15 | 16 | using namespace std; 17 | typedef long long ll; 18 | ll qpower(ll a, ll b,ll mod) 19 | { 20 | ll ans = 1; 21 | while(b > 0) { 22 | if(b & 1) ans = (ans * a) % mod; 23 | b >>= 1; 24 | a = (a * a) % mod; 25 | } 26 | return ans; 27 | } 28 | mapmp; 29 | void BSGS(ll y, ll z,ll p) 30 | { 31 | if(z >= p) { 32 | std::cout << "cannot find x!" << '\n'; 33 | return; 34 | } 35 | y %= p; 36 | z %= p; 37 | if(y == 0 && z == 0) { 38 | std::cout << "1" << '\n'; 39 | return; 40 | } 41 | if(y == 0 && z != 0) { 42 | std::cout << "cannot find x!" << '\n'; 43 | return; 44 | } 45 | mp.clear(); 46 | ll tmp = 1; 47 | ll power = qpower(y, p - 2, p); 48 | ll k = ceil((sqrt(p))); 49 | mp[z] = k + 1; 50 | for(int i = 1; i < k; i++) { 51 | tmp = tmp * power % p; 52 | ll t = tmp * z % p; 53 | if(!mp[t]) mp[t] = i; 54 | } 55 | tmp = 1; 56 | power = qpower(y,k,p); 57 | for(int i = 0; i < k; i++, tmp = tmp * power % p) 58 | { 59 | if(mp[tmp]) 60 | { 61 | if(mp[tmp] == k + 1) std::cout << i * k << '\n'; 62 | else std::cout << i * k + mp[tmp] << '\n'; 63 | return; 64 | } 65 | } 66 | std::cout << "cannot find x!" << '\n'; 67 | } -------------------------------------------------------------------------------- /Mathematics/Berlekamp-Massey.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | typedef long long ll; 4 | const double eps = 1e-7; 5 | const int maxn = 1e5 + 5; 6 | vector ps[maxn]; 7 | int fail[maxn]; 8 | double x[maxn], delta[maxn]; 9 | int n; 10 | int pn; 11 | /* 12 | 前提:必须符合线性递推,如: 13 | fib: 1 1 2 3 5 8 13 21 34 55 89 14 | */ 15 | int main() 16 | { 17 | while (~scanf("%d", &n)) // n 项 18 | { 19 | pn = 0; 20 | for (int i = 1; i <= n; i++) { 21 | scanf("%lf", &x[i]); //前 n项 22 | } 23 | for (int i = 1; i <= n; i++) 24 | { 25 | double dt = -x[i]; 26 | for (int j = 0; j < (int)ps[pn].size(); j++) 27 | { 28 | dt += x[i - j - 1] * ps[pn][j]; 29 | } 30 | delta[i] = dt; 31 | if (fabs(dt) <= eps) continue; 32 | fail[pn] = i; 33 | if(!pn) 34 | { 35 | ps[++pn].resize(1); 36 | continue; 37 | } 38 | vector&ls = ps[pn - 1]; 39 | double k = -dt / delta[fail[pn - 1]]; 40 | vector cur; 41 | cur.resize(i - fail[pn - 1] - 1); 42 | cur.push_back(-k); 43 | for(int j = 0; j < (int)ls.size();j++) 44 | { 45 | cur.push_back(ls[j] * k); 46 | } 47 | if((int)cur.size() < (int)ps[pn].size()) 48 | { 49 | cur.resize(ps[pn].size()); 50 | } 51 | for(int j = 0; j < (int)ps[pn].size(); j++) 52 | { 53 | cur[j] += ps[pn][j]; 54 | } 55 | ps[++pn] = cur; 56 | } 57 | int len = (int)ps[pn].size(); 58 | std::cout << "f[i]=" ; 59 | for (int i = 0; i < len; i++){ 60 | if(ps[pn][i] > 0 && i > 0)std::cout << "+"; 61 | if(ps[pn][i]==0)continue; 62 | printf("%g*f[i-%d]", ps[pn][i], i+1); 63 | } 64 | } 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /Mathematics/Berlekamp-Massey(Complete).cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | typedef long long ll; 4 | 5 | // n^2logk 6 | 7 | const ll mod=1000000007; 8 | ll qpower(ll a,ll b) 9 | { 10 | ll ans=1; 11 | while(b>0) { 12 | if(b&1) ans=(ans*a)%mod; 13 | b>>=1; 14 | a=(a*a)%mod; 15 | } 16 | return ans; 17 | } 18 | int t,n; 19 | namespace linear_seq 20 | { 21 | const int N=10010; 22 | ll res[N],base[N],_c[N],_md[N]; 23 | 24 | vector Md; 25 | void mul(ll *a,ll *b,int k) { 26 | for(int i = 0; i < k + k; i++) _c[i]=0; 27 | for(int i = 0; i < k; i++) { 28 | if(a[i]) { 29 | for(int j = 0; j < k; j++) { 30 | _c[i+j]=(_c[i+j]+a[i]*b[j])%mod; 31 | } 32 | } 33 | } 34 | for (int i=k+k-1;i>=k;i--) { 35 | if (_c[i]) 36 | for(int j = 0; j < (int)Md.size();j++) { 37 | _c[i-k+Md[j]]=(_c[i-k+Md[j]]-_c[i]*_md[Md[j]])%mod; 38 | } 39 | } 40 | for(int i = 0; i < k; i++) a[i]=_c[i]; 41 | } 42 | int solve(ll n,vector a,vector b) { // a 系数 b 初值 b[n+1]=a[0]*b[n]+... 43 | // printf("%d\n",int(b.size())); 44 | ll ans=0,pnt=0; 45 | int k=(int)a.size(); 46 | assert((int)a.size() == (int)b.size()); 47 | for(int i = 0; i < k; i++) { 48 | _md[k-1-i]=-a[i]; 49 | } 50 | _md[k]=1; 51 | Md.clear(); 52 | for(int i = 0; i < k; i++) { 53 | if (_md[i]!=0) Md.push_back(i); 54 | } 55 | for(int i = 0; i < k; i++) { 56 | res[i]=base[i]=0; 57 | } 58 | res[0]=1; 59 | while ((1LL<< pnt) <= n) pnt++; 60 | for (int p=pnt;p>=0;p--) 61 | { 62 | mul(res,res,k); 63 | if ((n>>p)&1) { 64 | for(int i=k-1;i>=0;i--) res[i+1]=res[i]; 65 | res[0]=0; 66 | for(int j = 0; j < (int)Md.size(); j++) { 67 | res[Md[j]]=(res[Md[j]]-res[k]*_md[Md[j]])%mod; 68 | } 69 | } 70 | } 71 | for(int i = 0; i < k; i++) { 72 | ans=(ans+res[i]*b[i])%mod; 73 | } 74 | if (ans<0) ans+=mod; 75 | return ans; 76 | } 77 | vector BM(vector s) { 78 | vector C(1,1),B(1,1); 79 | int L=0,m=1,b=1; 80 | for(int n = 0; n < (int)s.size(); n++) { 81 | ll d=0; 82 | for(int i = 0; i < L + 1; i++) { 83 | d=(d+(ll)C[i]*s[n-i])%mod; 84 | } 85 | if (d==0) ++m; 86 | else if (2*L<=n) { 87 | vector T=C; 88 | ll c=mod - d * qpower(b,mod-2)%mod; 89 | while ((int)C.size()<(int)B.size() + m) C.push_back(0); 90 | for(int i = 0; i < (int)B.size(); i++) { 91 | C[i+m]=(C[i+m]+c*B[i])%mod; 92 | } 93 | L=n+1-L; B=T; 94 | b=d; m=1; 95 | } 96 | else { 97 | ll c=mod - d * qpower(b,mod-2)%mod; 98 | while ((int)C.size()<(int)B.size() + m) C.push_back(0); 99 | for(int i = 0; i < (int)B.size(); i++) { 100 | C[i+m]=(C[i+m]+c*B[i])%mod; 101 | } 102 | ++m; 103 | } 104 | } 105 | for(int i = 0; i < (int)C.size(); i++) { 106 | printf("%dx[%d]%s",C[i],i,i+1==(int)C.size() ? "=0\n" : "+"); 107 | } 108 | return C; 109 | } 110 | int Doit(vector a,ll n) { 111 | vector c = BM(a); 112 | c.erase(c.begin()); 113 | for(int i = 0; i < (int)c.size(); i++) { 114 | c[i]=(mod-c[i])%mod; 115 | } 116 | return solve(n,c,vector(a.begin(),a.begin()+(int)c.size())); 117 | } 118 | }; 119 | using namespace linear_seq; 120 | int main() 121 | { 122 | scanf("%d",&t); 123 | while(t--) 124 | { 125 | scanf("%d",&n); 126 | printf("%d\n",Doit(vector{1 ,1 ,2, 3 ,5 ,8 ,13 ,21 ,34 ,55 ,89},n-1)); 127 | } 128 | return 0; 129 | } 130 | -------------------------------------------------------------------------------- /Mathematics/CRT(模数不互质).cpp: -------------------------------------------------------------------------------- 1 | /** 2 | http://blog.csdn.net/tree__water/article/details/52140927?locationNum=11 3 | 4 | Chinese-Remainder-Theorem 5 | 6 | 中国剩余定理(模数不必不互质) 7 | 8 | 模数不互质可以通过合并方程组来求解。 9 | */ 10 | #include 11 | using namespace std; 12 | typedef long long ll; 13 | ll Mod; 14 | 15 | ll gcd(ll a, ll b) 16 | { 17 | if(b==0) 18 | return a; 19 | return gcd(b,a%b); 20 | } 21 | 22 | ll Extend_Euclid(ll a, ll b, ll&x, ll& y) 23 | { 24 | if(b==0) 25 | { 26 | x=1,y=0; 27 | return a; 28 | } 29 | ll d = Extend_Euclid(b,a%b,x,y); 30 | ll t = x; 31 | x = y; 32 | y = t - a/b*y; 33 | return d; 34 | } 35 | 36 | //a在模n乘法下的逆元,没有则返回-1 37 | ll inv(ll a, ll n) 38 | { 39 | ll x,y; 40 | ll t = Extend_Euclid(a,n,x,y); 41 | if(t != 1) 42 | return -1; 43 | return (x%n+n)%n; 44 | } 45 | 46 | //将两个方程合并为一个 47 | bool merge(ll a1, ll n1, ll a2, ll n2, ll& a3, ll& n3) 48 | { 49 | ll d = gcd(n1,n2); 50 | ll c = a2-a1; 51 | if(c%d) 52 | return false; 53 | c = (c%n2+n2)%n2; 54 | c /= d; 55 | n1 /= d; 56 | n2 /= d; 57 | c *= inv(n1,n2); 58 | c %= n2; 59 | c *= n1*d; 60 | c += a1; 61 | n3 = n1*n2*d; 62 | a3 = (c%n3+n3)%n3; 63 | return true; 64 | } 65 | 66 | //求模线性方程组x=ai(mod ni),ni可以不互质 67 | ll crt(int len, ll* a, ll* n) 68 | { 69 | ll a1=a[0],n1=n[0]; 70 | ll a2,n2; 71 | for(int i = 1; i < len; i++) 72 | { 73 | ll aa,nn; 74 | a2 = a[i],n2=n[i]; 75 | if(!merge(a1,n1,a2,n2,aa,nn)) 76 | return -1; 77 | a1 = aa; 78 | n1 = nn; 79 | } 80 | Mod = n1; 81 | return (a1%n1+n1)%n1; 82 | } 83 | ll a[1000],b[1000]; 84 | int main() 85 | { 86 | 87 | int n; // n个同余方程组 88 | while(scanf("%d",&n)!=EOF) 89 | { 90 | for(int i = 0; i < n; i++) 91 | scanf("%I64d %I64d",&a[i],&b[i]); 92 | printf("%I64d\n",crt(n,a,b)); 93 | } 94 | return 0; 95 | } 96 | -------------------------------------------------------------------------------- /Mathematics/CRT(模数互质).cpp: -------------------------------------------------------------------------------- 1 | 2 | //Chinese-Remainder-Theorem 3 | // 模必须互质 4 | #include 5 | using namespace std; 6 | typedef long long ll; 7 | 8 | // a solution of ax + by = gcd(a, b) 9 | void extend_Euclid(ll a, ll b, ll *x, ll *y, ll *g) 10 | { 11 | if(a == 0) 12 | { 13 | *x = 0, *y = 1 , *g = b; 14 | return; 15 | } 16 | ll x1,y1; 17 | extend_Euclid(b%a, a, &x1, &y1, g); 18 | *x = y1 - (b/a)*x1; 19 | *y = x1; 20 | } 21 | //Chinese-remainder-theorem 22 | ll crt(ll* a, ll* w, int len)//a存放的是余数,w存放的是两两互质的模数 23 | { 24 | ll P = 1; 25 | for(int i=0; i a[j]) ++counted; 17 | result = result + counted * factory[len - i - 1]; 18 | } 19 | return result; 20 | } 21 | 22 | bool h[13]; 23 | 24 | void UnCantor(int x, int res[], int len) { 25 | int i, j, l, t; 26 | for (i = 1; i <= len; i++) h[i] = false; 27 | for (i = 1; i <= len; i++) { 28 | t = x / factory[len - i]; 29 | x -= t * factory[len - i]; 30 | for (j = 1, l = 0; l <= t; j++) 31 | if (!h[j]) l++; 32 | j--; 33 | h[j] = true; 34 | res[i - 1] = j; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Mathematics/Check_primitive_root.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | g^d ≡ 1 (mod p) ,gcd(g,m) = 1 4 | 如果g是P的原根,那么g的(1…P-1)次幂 mod P的结果一定互不相同。 5 | 6 | 检查 g 是否是模 p 意义下的原根. 7 | 8 | */ 9 | 10 | ll qpower(ll x,ll n,ll m) 11 | { 12 | long long res = 1; 13 | while(n > 0){ 14 | if(n & 1) res = (res * x) % m; 15 | x = (x * x) % m; 16 | n >>= 1; 17 | } 18 | return res; 19 | } 20 | // bool check_primitive_root(ll g, ll p) 21 | // { 22 | // ll n = p - 1; 23 | // std::vector divsior; 24 | // for(ll i = 2; i * i <= n; i++) { 25 | // if (n % i == 0) { 26 | // divsior.push_back(i); 27 | // while (n % i == 0) n /= i; 28 | // } 29 | // } 30 | // if(n > 1) divsior.push_back(n); 31 | // 32 | // for(auto &a : divsior) 33 | // { 34 | // if(qpower(g, (p - 1) / a, p) == 1) return false; 35 | // } 36 | // return true; 37 | // } 38 | bool check_primitive_root(ll g, ll p) 39 | { 40 | if (qpower(g,(p-1)/5,p)==1) return false; 41 | return true; 42 | } -------------------------------------------------------------------------------- /Mathematics/Determinant.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: zhaoyang.liang 3 | * @Github: https://github.com/LzyRapx 4 | * @Date: 2019-10-21 22:16:19 5 | */ 6 | #include 7 | #include 8 | #include 9 | #define MAXN 505 10 | using namespace std; 11 | typedef vector vec; 12 | typedef vector mat; 13 | 14 | /* 15 | 给一个 n*n 的行列式 A 和模数 mod ,求 A 的秩模 mod 16 | */ 17 | int n; 18 | int det_mod(mat A, int mod) { 19 | int n = A.size(); 20 | for (int i = 0; i < n; i++) { 21 | for (int j = 0; j < n; j++) { 22 | A[i][j] %= mod; 23 | } 24 | } 25 | 26 | int ans = 1; 27 | for (int i = 0; i < n; i++) { 28 | for (int j = i + 1; j < n; j++) { 29 | while (A[j][i] != 0) { 30 | int t = A[i][i] / A[j][i]; 31 | for (int k = 0; k < n; k++) { 32 | A[i][k] = A[i][k] - A[j][k] * t; 33 | swap(A[i][k], A[j][k]); 34 | } 35 | ans = -ans; 36 | } 37 | if (A[i][i] == 0) return 0; 38 | } 39 | ans = ans * A[i][i]; 40 | } 41 | return (ans % mod + mod) % mod; 42 | } 43 | int main() { 44 | int mod; 45 | cin >> n >> mod; 46 | mat A(n, vec(n)); 47 | for (int i = 0; i < n; i++) { 48 | for (int j = 0; j < n; j++) { 49 | cin >> A[i][j]; 50 | } 51 | } 52 | printf("%d\n", det_mod(A, mod)); 53 | return 0; 54 | } -------------------------------------------------------------------------------- /Mathematics/Dirichlet卷积.cpp: -------------------------------------------------------------------------------- 1 | // 狄利克雷卷积: 2 | // 对于两个算术函数f和g,定义其狄利克雷卷积为f*g,其中f*g(n)=\sum_{d|n} 3 | // f(d)g(n/d)} 4 | // 狄利克雷卷积满足很多性质: 5 | // 交换律:f*g=g*f, 6 | // 结合律:(f*g)*h=f*(g*h) 7 | // 逐点加法的分配律:f*(g+h)=f*g+f*h。 8 | // 若f,g是积性函数,那么f*g也是积性函数。 9 | // 狄利克雷卷积可以用O(nlogn)的筛法预处理出来。无脑枚举所有数的倍数。 10 | // http://jcvb.is-programmer.com/posts/41846.html 11 | int f[MAXN], g[MAXN], h[MAXN] = {0}; 12 | void calc(int n) { 13 | for (int i = 1; i * i <= n; i++) 14 | for (int j = i; i * j <= n; j++) 15 | if (j == i) 16 | h[i * j] += f[i] * g[i]; 17 | else 18 | h[i * j] += f[i] * g[j] + f[j] * g[i]; 19 | } -------------------------------------------------------------------------------- /Mathematics/EX_BSGS.cpp: -------------------------------------------------------------------------------- 1 | // 扩展大步小步法( Extend Baby-Step-Giant-Step,简称BSGS) 2 | // https://www.lydsy.com/JudgeOnline/problem.php?id=1467 3 | // http://poj.org/problem?id=3243 4 | // 给定a,b,p,计算满足 a^x ≡ b ( mod p)的最小非负整数x, p为任意整数 5 | // 复杂度:O(sqrt(p)) 6 | 7 | typedef long long ll; 8 | ll qpower(ll a, ll b,ll mod) 9 | { 10 | long long ans=1; 11 | while(b>0) { 12 | if(b&1) ans=(ans*a)%mod; 13 | b>>=1; 14 | a=(a*a)%mod; 15 | } 16 | return ans; 17 | } 18 | mapmp; 19 | void EXBSGS(ll a, ll b,ll p) 20 | { 21 | if(b >= p) { 22 | std::cout << "cannot find x!" << '\n'; 23 | return; 24 | } 25 | a %= p; 26 | b %= p; 27 | if(b == 1) { 28 | std::cout << "0" << '\n';return; 29 | } 30 | ll t = 0,d = 1,k = 0; 31 | while((t = __gcd(a,p)) != 1) 32 | { 33 | if(b % t) { 34 | std::cout << "No Solution" << '\n'; 35 | return; 36 | } 37 | ++k,b /= t,p /= t, d = d * (a / t ) % p; 38 | if(b == d){ 39 | std::cout << k << '\n'; 40 | return; 41 | } 42 | } 43 | mp.clear(); 44 | ll m = ceil(sqrt(p)); 45 | ll a_m = qpower(a,m,p); 46 | ll mul = b; 47 | for(ll j = 1;j <= m; j++) 48 | { 49 | mul = mul * a % p; 50 | mp[mul] = j; 51 | } 52 | for(ll i = 1;i <= m; i++) 53 | { 54 | d = d * a_m % p; 55 | if(mp[d]) { 56 | std::cout << i * m - mp[d] + k << '\n'; 57 | return; 58 | } 59 | } 60 | std::cout << "No Solution" << '\n'; 61 | } -------------------------------------------------------------------------------- /Mathematics/Euler_Function.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | int phi[1000]; 4 | 5 | /* 6 | 返回[1,n]中和n互素的个数 7 | */ 8 | void getPhi(int n) 9 | { 10 | int i, j, pNum = 0 ; 11 | memset(phi, 0, sizeof(phi)) ; 12 | phi[1] = 1 ; 13 | for(i = 2; i < n; i++) 14 | { 15 | if(!phi[i]) 16 | { 17 | for(j = i; j < n; j += i) 18 | { 19 | if(!phi[j]) 20 | phi[j] = j; 21 | phi[j] = phi[j] / i * (i - 1); 22 | } 23 | } 24 | } 25 | } 26 | 27 | int euler(int n) 28 | { 29 | int ret = n; 30 | int i; 31 | for(i = 2 ; i * i <= n ; i ++) 32 | { 33 | if(n % i == 0) 34 | { 35 | ret = ret - ret / i; 36 | while(n % i == 0) 37 | { 38 | n /= i; 39 | } 40 | } 41 | } 42 | if(n > 1) 43 | { 44 | ret = ret - ret / n; 45 | } 46 | return ret; 47 | } 48 | /* 49 | 容斥: 50 | 返回:[1,x]中与p互素的个数。 51 | */ 52 | std::vector divsior[1000010]; 53 | // divsior[p][j] represent the j_th divsior of p is divsior[p][j] 54 | void init() 55 | { 56 | for(int i=2;i<=1e6;i++) { 57 | if(divsior[i].empty()) { 58 | for(int j=i;j<=1e6;j+=i) { 59 | divsior[j].push_back(i); 60 | } 61 | } 62 | } 63 | } 64 | //return : [1,x]中与 p互质的数的个数 65 | ll query(ll x,ll p) 66 | { 67 | ll ans = 0; 68 | for(int i = 0;i < (1 << divsior[p].size());i++) { 69 | int cnt = 0; 70 | int v = 1; 71 | for(int j = 0;j < (int)divsior[p].size();j++) { 72 | if((1< Complex; 2 | 3 | const double PI = acos(-1.0); 4 | 5 | void radar(Complex *y, int len) { 6 | for (int i = 1, j = len / 2; i < len - 1; i++) { 7 | if (i < j) swap(y[i], y[j]); 8 | int k = len / 2; 9 | while (j >= k) { 10 | j -= k; 11 | k /= 2; 12 | } 13 | if (j < k) j += k; 14 | } 15 | } 16 | 17 | void fft(Complex *y, int len, int op) { 18 | radar(y, len); 19 | for (int h = 2; h <= len; h <<= 1) { 20 | double ang = op * 2 * PI / h; 21 | Complex wn(cos(ang), sin(ang)); 22 | for (int j = 0; j < len; j += h) { 23 | Complex w(1, 0); 24 | for (int k = j; k < j + h / 2; k++) { 25 | Complex u = y[k]; 26 | Complex t = w * y[k + h / 2]; 27 | y[k] = u + t; 28 | y[k + h / 2] = u - t; 29 | w = w * wn; 30 | } 31 | } 32 | } 33 | if (op == -1) 34 | for (int i = 0; i < len; i++) y[i] /= len; 35 | } 36 | 37 | const int N = 200005, M = 313; 38 | 39 | Complex A[N << 1], B[N << 1]; 40 | 41 | int f[N], a[N]; 42 | 43 | void cdq(int l, int r) { 44 | if (l == r) return; 45 | int mid = (l + r) >> 1; 46 | cdq(l, mid); 47 | int len = 1; 48 | while (len <= r - l + 1) len <<= 1; 49 | for (int i = 0; i < len; i++) { 50 | A[i] = Complex(l + i <= mid ? f[l + i] : 0, 0); 51 | B[i] = Complex(l + i + 1 <= r ? a[i + 1] : 0, 0); 52 | } 53 | fft(A, len, 1); 54 | fft(B, len, 1); 55 | for (int i = 0; i < len; i++) A[i] *= B[i]; 56 | fft(A, len, -1); 57 | for (int i = mid + 1; i <= r; i++) { 58 | f[i] += fmod(A[i - l - 1].real(), M) + 0.5; 59 | if (f[i] >= M) f[i] -= M; 60 | } 61 | cdq(mid + 1, r); 62 | } 63 | 64 | int main() { 65 | int n; 66 | double clock_t = clock(); 67 | ios_base::sync_with_stdio(0); 68 | while (~scanf("%d", &n) && n) { 69 | for (int i = 1; i <= n; i++) { 70 | scanf("%d", a + i); 71 | a[i] %= M; 72 | } 73 | memset(f, 0, sizeof(f)); 74 | f[0] = 1; 75 | cdq(0, n); 76 | printf("%d\n", f[n]); 77 | } 78 | #ifdef LOCAL 79 | printf("\nTime cost %.3fs\n",1.0 * (clock() - colck_t); 80 | #endif 81 | return 0; 82 | } -------------------------------------------------------------------------------- /Mathematics/FFT大整数乘法.cpp: -------------------------------------------------------------------------------- 1 | // FFT 大整数乘法 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | const int N = 500005; 10 | const double pi = acos(-1.0); 11 | 12 | char s1[N], s2[N]; 13 | int len, res[N]; 14 | 15 | struct Complex { 16 | double r, i; 17 | Complex(double r = 0, double i = 0) : r(r), i(i){}; 18 | Complex operator+(const Complex &rhs) { 19 | return Complex(r + rhs.r, i + rhs.i); 20 | } 21 | Complex operator-(const Complex &rhs) { 22 | return Complex(r - rhs.r, i - rhs.i); 23 | } 24 | Complex operator*(const Complex &rhs) { 25 | return Complex(r * rhs.r - i * rhs.i, i * rhs.r + r * rhs.i); 26 | } 27 | } va[N], vb[N]; 28 | 29 | //雷德算法--倒位序 30 | void rader(Complex F[], 31 | int len) // len = 2^M,reverse F[i] with F[j] j为i二进制反转 32 | { 33 | int j = len >> 1; 34 | for (int i = 1; i < len - 1; ++i) { 35 | if (i < j) swap(F[i], F[j]); // reverse 36 | int k = len >> 1; 37 | while (j >= k) { 38 | j -= k; 39 | k >>= 1; 40 | } 41 | if (j < k) j += k; 42 | } 43 | } 44 | // FFT实现 45 | void FFT(Complex F[], int len, int t) { 46 | rader(F, len); 47 | for (int h = 2; h <= len; h <<= 1) //分治后计算长度为h的DFT 48 | { 49 | Complex wn(cos(-t * 2 * pi / h), 50 | sin(-t * 2 * pi / h)); //单位复根e^(2*PI/m)用欧拉公式展开 51 | for (int j = 0; j < len; j += h) { 52 | Complex E(1, 0); //旋转因子 53 | for (int k = j; k < j + h / 2; ++k) { 54 | Complex u = F[k]; 55 | Complex v = E * F[k + h / 2]; 56 | F[k] = u + v; //蝴蝶合并操作 57 | F[k + h / 2] = u - v; 58 | E = E * wn; //更新旋转因子 59 | } 60 | } 61 | } 62 | if (t == -1) // IDFT 63 | for (int i = 0; i < len; ++i) F[i].r /= len; 64 | } 65 | //求卷积 66 | void Conv(Complex a[], Complex b[], int len) //求卷积 67 | { 68 | FFT(a, len, 1); 69 | FFT(b, len, 1); 70 | for (int i = 0; i < len; ++i) a[i] = a[i] * b[i]; 71 | FFT(a, len, -1); 72 | } 73 | 74 | void init(char *s1, char *s2) { 75 | int n1 = strlen(s1), n2 = strlen(s2); 76 | len = 1; 77 | while (len < 2 * n1 || len < 2 * n2) len <<= 1; 78 | int i; 79 | for (i = 0; i < n1; ++i) { 80 | va[i].r = s1[n1 - i - 1] - '0'; 81 | va[i].i = 0; 82 | } 83 | while (i < len) { 84 | va[i].r = va[i].i = 0; 85 | ++i; 86 | } 87 | for (i = 0; i < n2; ++i) { 88 | vb[i].r = s2[n2 - i - 1] - '0'; 89 | vb[i].i = 0; 90 | } 91 | while (i < len) { 92 | vb[i].r = vb[i].i = 0; 93 | ++i; 94 | } 95 | } 96 | 97 | void gao() { 98 | Conv(va, vb, len); 99 | memset(res, 0, sizeof res); 100 | for (int i = 0; i < len; ++i) { 101 | res[i] = va[i].r + 0.5; 102 | } 103 | for (int i = 0; i < len; ++i) { 104 | res[i + 1] += res[i] / 10; 105 | res[i] %= 10; 106 | } 107 | int high = 0; 108 | for (int i = len - 1; i >= 0; --i) { 109 | if (res[i]) { 110 | high = i; 111 | break; 112 | } 113 | } 114 | for (int i = high; i >= 0; --i) putchar('0' + res[i]); 115 | puts(""); 116 | } 117 | 118 | int main() { 119 | while (scanf("%s %s", s1, s2) == 2) { 120 | init(s1, s2); 121 | gao(); 122 | } 123 | return 0; 124 | } 125 | -------------------------------------------------------------------------------- /Mathematics/Fib数模n的循环节.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | // http://blog.csdn.net/acdreamers/article/details/10983813 7 | using namespace std; 8 | typedef unsigned long long LL; 9 | 10 | const int M = 2; 11 | 12 | struct Matrix { 13 | LL m[M][M]; 14 | }; 15 | 16 | Matrix A; 17 | Matrix I = {1, 0, 0, 1}; 18 | 19 | Matrix multi(Matrix a, Matrix b, LL MOD) { 20 | Matrix c; 21 | for (int i = 0; i < M; i++) { 22 | for (int j = 0; j < M; j++) { 23 | c.m[i][j] = 0; 24 | for (int k = 0; k < M; k++) 25 | c.m[i][j] = 26 | (c.m[i][j] % MOD + (a.m[i][k] % MOD) * (b.m[k][j] % MOD) % MOD) % 27 | MOD; 28 | c.m[i][j] %= MOD; 29 | } 30 | } 31 | return c; 32 | } 33 | 34 | Matrix power(Matrix a, LL k, LL MOD) { 35 | Matrix ans = I, p = a; 36 | while (k) { 37 | if (k & 1) { 38 | ans = multi(ans, p, MOD); 39 | k--; 40 | } 41 | k >>= 1; 42 | p = multi(p, p, MOD); 43 | } 44 | return ans; 45 | } 46 | 47 | LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a; } 48 | 49 | const int N = 400005; 50 | const int NN = 5005; 51 | 52 | LL num[NN], pri[NN]; 53 | LL fac[NN]; 54 | int cnt, c; 55 | 56 | bool prime[N]; 57 | int p[N]; 58 | int k; 59 | 60 | void isprime() { 61 | k = 0; 62 | memset(prime, true, sizeof(prime)); 63 | for (int i = 2; i < N; i++) { 64 | if (prime[i]) { 65 | p[k++] = i; 66 | for (int j = i + i; j < N; j += i) prime[j] = false; 67 | } 68 | } 69 | } 70 | 71 | LL quick_mod(LL a, LL b, LL m) { 72 | LL ans = 1; 73 | a %= m; 74 | while (b) { 75 | if (b & 1) { 76 | ans = ans * a % m; 77 | b--; 78 | } 79 | b >>= 1; 80 | a = a * a % m; 81 | } 82 | return ans; 83 | } 84 | 85 | LL legendre(LL a, LL p) { 86 | if (quick_mod(a, (p - 1) >> 1, p) == 1) 87 | return 1; 88 | else 89 | return -1; 90 | } 91 | 92 | void Solve(LL n, LL pri[], LL num[]) { 93 | cnt = 0; 94 | LL t = (LL)sqrt(1.0 * n); 95 | for (int i = 0; p[i] <= t; i++) { 96 | if (n % p[i] == 0) { 97 | int a = 0; 98 | pri[cnt] = p[i]; 99 | while (n % p[i] == 0) { 100 | a++; 101 | n /= p[i]; 102 | } 103 | num[cnt] = a; 104 | cnt++; 105 | } 106 | } 107 | if (n > 1) { 108 | pri[cnt] = n; 109 | num[cnt] = 1; 110 | cnt++; 111 | } 112 | } 113 | 114 | void Work(LL n) { 115 | c = 0; 116 | LL t = (LL)sqrt(1.0 * n); 117 | for (int i = 1; i <= t; i++) { 118 | if (n % i == 0) { 119 | if (i * i == n) 120 | fac[c++] = i; 121 | else { 122 | fac[c++] = i; 123 | fac[c++] = n / i; 124 | } 125 | } 126 | } 127 | } 128 | 129 | LL find_loop(LL n) { 130 | Solve(n, pri, num); 131 | LL ans = 1; 132 | for (int i = 0; i < cnt; i++) { 133 | LL record = 1; 134 | if (pri[i] == 2) 135 | record = 3; 136 | else if (pri[i] == 3) 137 | record = 8; 138 | else if (pri[i] == 5) 139 | record = 20; 140 | else { 141 | if (legendre(5, pri[i]) == 1) 142 | Work(pri[i] - 1); 143 | else 144 | Work(2 * (pri[i] + 1)); 145 | sort(fac, fac + c); 146 | for (int k = 0; k < c; k++) { 147 | Matrix a = power(A, fac[k] - 1, pri[i]); 148 | LL x = (a.m[0][0] % pri[i] + a.m[0][1] % pri[i]) % pri[i]; 149 | LL y = (a.m[1][0] % pri[i] + a.m[1][1] % pri[i]) % pri[i]; 150 | if (x == 1 && y == 0) { 151 | record = fac[k]; 152 | break; 153 | } 154 | } 155 | } 156 | for (int k = 1; k < num[i]; k++) record *= pri[i]; 157 | ans = ans / gcd(ans, record) * record; 158 | } 159 | return ans; 160 | } 161 | 162 | void Init() { 163 | A.m[0][0] = 1; 164 | A.m[0][1] = 1; 165 | A.m[1][0] = 1; 166 | A.m[1][1] = 0; 167 | } 168 | 169 | int main() { 170 | LL n; 171 | Init(); 172 | isprime(); 173 | while (cin >> n) cout << find_loop(n) << endl; 174 | return 0; 175 | } 176 | -------------------------------------------------------------------------------- /Mathematics/Guass.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | const int maxn = 1234; 4 | 5 | // https://www.luogu.org/problemnew/show/P3389 6 | 7 | const double eps = 1e-7; 8 | int n; 9 | double a[maxn][maxn]; 10 | bool Gauss() { 11 | int r; 12 | double f; 13 | for (int i = 0; i < n; i++) { 14 | r = i; 15 | for (int j = i + 1; j < n; j++) { 16 | if (fabs(a[j][i]) > fabs(a[r][i])) r = j; 17 | } 18 | if (fabs(a[r][i]) < eps) return false; 19 | if (r != i) { 20 | for (int j = 0; j <= n; j++) swap(a[r][j], a[i][j]); 21 | } 22 | for (int k = i + 1; k < n; k++) { 23 | f = a[k][i] / a[i][i]; 24 | for (int j = i; j <= n; j++) { 25 | a[k][j] -= f * a[i][j]; 26 | } 27 | } 28 | } 29 | for (int i = n - 1; i >= 0; --i) { 30 | for (int j = i + 1; j < n; ++j) a[i][n] -= a[j][n] * a[i][j]; 31 | a[i][n] /= a[i][i]; 32 | } 33 | return true; 34 | } 35 | int main(int argc, char const *argv[]) { 36 | std::cin >> n; 37 | for (int i = 0; i < n; i++) { 38 | for (int j = 0; j <= n; j++) { 39 | int x; 40 | std::cin >> x; 41 | a[i][j] = x; 42 | } 43 | } 44 | if (Gauss() == 0) 45 | std::cout << "No Solution" << '\n'; 46 | else { 47 | for (int i = 0; i < n; i++) { 48 | printf("%.2lf\n", a[i][n]); 49 | } 50 | } 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /Mathematics/MTT.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | typedef long long ll; 4 | const long double PI=std::acos(-1); 5 | const int maxn = 5e5+100; 6 | const int M = 32768; 7 | 8 | // https://www.luogu.org/problemnew/show/P4245 9 | // 求两个多项式的卷积,系数对P取模,不保证P可以分解成P = a*2^k-1 10 | // 即对NTT不适合的情况,就是任意模的情况 11 | /* 12 | MTT就是: 13 | 拆系数+FFT 14 | 基本上就是找个模数 15 | 然后拆成4个多项式,分别是第一个多项式 / 模数 %模数 第二个多项式 / 模数 %模数 的值 16 | 然后两两相乘,结果 乘上对应项数的模数次方然后%要取的模数 17 | 这样的话是做4次DFT,4次IDFT 18 | 然而单位复根的精度会出问题 19 | 可以预处理,注意精度问题,开long double 20 | */ 21 | 22 | struct Complex{ 23 | long double real,imag; 24 | Complex(){}; 25 | Complex(long double _real,long double _imag):real(_real),imag(_imag){} 26 | }; 27 | inline Complex operator + (Complex x,Complex y){return (Complex){x.real+y.real,x.imag+y.imag};} 28 | inline Complex operator - (Complex x,Complex y){return (Complex){x.real-y.real,x.imag-y.imag};} 29 | inline Complex operator * (Complex x,Complex y){return (Complex){x.real*y.real-x.imag*y.imag,x.real*y.imag+y.real*x.imag};} 30 | int F[maxn],G[maxn],rev[maxn]; 31 | int l; 32 | inline void FFT(Complex *a,int n,int f) 33 | { 34 | for(int i=0;i>1]>>1)|((i&1)<<(l-1)); 36 | } 37 | for(int i=0;i> n >> m >> p; 95 | for(int i=0;i<=n;i++) { 96 | std::cin >> F[i]; 97 | } 98 | for(int i=0;i<=m;i++) { 99 | std::cin >> G[i]; 100 | } 101 | MTT(); // F 和 G 的卷积 ans 102 | for(int i = 0; i <= n; i++) { 103 | std::cout << ans[i] << ' '; 104 | } 105 | std::cout << '\n'; 106 | return 0; 107 | } 108 | -------------------------------------------------------------------------------- /Mathematics/Meissel-Lehmer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | typedef long long ll; 6 | 7 | /* 8 | * O(N^(2/3)) 9 | * declare in global or heap 10 | */ 11 | struct Melssel_Lehmer 12 | { 13 | static const int N = 6e6 + 2; 14 | bool notprime[N]; 15 | int prime[N], pi[N]; 16 | static const int M = 7; 17 | static const int PM = 2 * 3 * 5 * 7 * 11 * 13 * 17; 18 | int phi[PM + 1][M + 1], sz[M + 1]; 19 | Melssel_Lehmer() 20 | { 21 | int cnt = 0; 22 | notprime[0] = notprime[1] = true; 23 | pi[0] = pi[1] = 0; 24 | for (int i = 2; i < N; ++i) 25 | { 26 | if (!notprime[i]) 27 | prime[++cnt] = i; 28 | pi[i] = cnt; 29 | for (int j = 1; j <= cnt && i * prime[j] < N; ++j) 30 | { 31 | notprime[i * prime[j]] = true; 32 | if (i % prime[j] == 0) 33 | break; 34 | } 35 | } 36 | sz[0] = 1; 37 | for (int i = 0; i <= PM; ++i) 38 | phi[i][0] = i; 39 | for (int i = 1; i <= M; ++i) 40 | { 41 | sz[i] = prime[i] * sz[i - 1]; 42 | for (int j = 1; j <= PM; ++j) 43 | phi[j][i] = phi[j][i - 1] - phi[j / prime[i]][i - 1]; 44 | } 45 | } 46 | int sqrt2(ll x) 47 | { 48 | ll r = (ll)sqrt(x - 0.1); 49 | while (r * r <= x) 50 | ++r; 51 | return r - 1; 52 | } 53 | int sqrt3(ll x) 54 | { 55 | ll r = (ll)cbrt(x - 0.1); 56 | while (r * r * r <= x) 57 | ++r; 58 | return r - 1; 59 | } 60 | ll getphi(ll x, ll s) 61 | { 62 | if (s == 0) 63 | return x; 64 | if (s <= M) 65 | return phi[x % sz[s]][s] + (x / sz[s]) * phi[sz[s]][s]; 66 | if (x <= prime[s] * prime[s]) 67 | return pi[x] - s + 1; 68 | if (x <= prime[s] * prime[s] * prime[s] && x < N) 69 | { 70 | int s2x = pi[sqrt2(x)]; 71 | ll ans = pi[x] - (s2x + s - 2) * (s2x - s + 1) / 2; 72 | for (int i = s + 1; i <= s2x; ++i) 73 | ans += pi[x / prime[i]]; 74 | return ans; 75 | } 76 | return getphi(x, s - 1) - getphi(x / prime[s], s - 1); 77 | } 78 | // https://oeis.org/A006880 79 | ll getpi(ll x) // return number of primes < 10^n. (1 <= n <= 13) faster 80 | { 81 | if (x < N) 82 | return pi[x]; 83 | ll ans = getphi(x, pi[sqrt3(x)]) + pi[sqrt3(x)] - 1; 84 | for (int i = pi[sqrt3(x)] + 1, ed = pi[sqrt2(x)]; i <= ed; ++i) 85 | ans -= getpi(x / prime[i]) - i + 1; 86 | return ans; 87 | } 88 | // https://oeis.org/A006880 89 | ll solve(ll x) // return number of primes < 10^n. (1 <= n <= 13) slower 90 | { 91 | if (x < N) 92 | return pi[x]; 93 | int a = (int)solve(sqrt2(sqrt2(x))); 94 | int b = (int)solve(sqrt2(x)); 95 | int c = (int)solve(sqrt3(x)); 96 | ll sum = getphi(x, a) + (ll)(b + a - 2) * (b - a + 1) / 2; 97 | for (int i = a + 1; i <= b; i++) 98 | { 99 | ll w = x / prime[i]; 100 | sum -= solve(w); 101 | if (i > c) 102 | continue; 103 | ll lim = solve(sqrt2(w)); 104 | for (int j = i; j <= lim; j++) 105 | { 106 | sum -= solve(w / prime[j]) - (j - 1); 107 | } 108 | } 109 | return sum; 110 | } 111 | }; 112 | Melssel_Lehmer solver; 113 | 114 | int main(int argc, char *argv[]) 115 | { 116 | cout << solver.getpi(10) << endl; 117 | cout << solver.getpi(100) << endl; 118 | cout << solver.getpi(1000) << endl; 119 | cout << solver.getpi(10000) << endl; 120 | clock_t start, end; 121 | start = clock(); 122 | cout << solver.getpi(1e13) << endl; 123 | end = clock(); 124 | printf("spent time=%f\n", (float)(end - start) * 1000 / CLOCKS_PER_SEC); 125 | start = clock(); 126 | cout << solver.solve(1e13) << endl; 127 | end = clock(); 128 | printf("spent time=%f\n", (float)(end - start) * 1000 / CLOCKS_PER_SEC); 129 | return 0; 130 | } -------------------------------------------------------------------------------- /Mathematics/[1,n]与a互素个数.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | [1,n]与a互素个数 O(sqrt n) 4 | 先对a分解质因数 5 | 然后用容斥原理 6 | */ 7 | 8 | int fac[50]; 9 | int solve(int n, int a) { 10 | int i, j, up, t, cnt = 0, sum = 0, flag; 11 | for (i = 2; i * i <= a; i++) 12 | if (a % i == 0) { 13 | fac[cnt++] = i; 14 | while (a % i == 0) a /= i; 15 | } 16 | if (a > 1) fac[cnt++] = a; 17 | up = 1 << cnt; 18 | for (i = 1; i < up; i++) { //容斥原理,二进制枚举 19 | flag = 0, t = 1; 20 | for (j = 0; j < cnt; j++) { 21 | if (i & (1 << j)) { 22 | flag ^= 1; 23 | t *= fac[j]; 24 | } 25 | } 26 | sum += flag ? n / t : -(n / t); 27 | } 28 | return n - sum; 29 | } 30 | -------------------------------------------------------------------------------- /Mathematics/bernoulli_number.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | bernoulli方程 4 | Sn(m)=1^n+2^n+...+(m-1)^n 5 | => Sn(m)=1/(m+1)(0~m)ΣC(m+1,k)Bk(m^(n+1-k)) 6 | 其中:B0=1 , (0,m)ΣC(m+1,k)Bk=0 7 | */ 8 | 9 | ll B[N][2], C[N][N], f[N][2]; 10 | int n, m; // n为幂大小 11 | 12 | ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; } 13 | ll lcm(ll a, ll b) { return a / gcd(a, b) * b; } 14 | 15 | void getC(int n) { 16 | int i, j; 17 | n++; 18 | for (i = 0; i <= n; i++) C[i][0] = C[i][i] = 1; 19 | for (i = 2; i <= n; i++) { 20 | for (j = 1; j < n; j++) { 21 | C[i][j] = C[i - 1][j - 1] + C[i - 1][j]; 22 | } 23 | } 24 | } 25 | 26 | void bernoulli(int n) //得到B数组 27 | { 28 | int i, m; 29 | ll s[2], b[2], l, g; 30 | B[0][0] = 1; 31 | B[0][1] = 1; 32 | for (m = 1; m <= n; m++) { 33 | s[0] = 1, s[1] = 1; 34 | for (i = 1; i < m; i++) { 35 | b[0] = C[m + 1][i] * B[i][0]; 36 | b[1] = B[i][1]; 37 | l = lcm(s[1], b[1]); 38 | s[0] = l / s[1] * s[0] + l / b[1] * b[0]; 39 | s[1] = l; 40 | } 41 | s[0] = -s[0]; 42 | if (s[0]) { 43 | g = gcd(s[0], s[1] * C[m + 1][m]); 44 | B[m][0] = s[0] / g; 45 | B[m][1] = s[1] * C[m + 1][m] / g; 46 | } else 47 | B[m][0] = 0, B[m][1] = 1; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Mathematics/factorial.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | factorial相关 4 | -求n!某个因子k的个数 n!=(k^m)*(m!)*a 5 | 推导: 6 | n!=n*(n-1)*(n-2)*......3*2*1 7 | =(k*2k*3k.....*mk)*a a是不含因子k的数的乘积,显然m=n/k; 8 | =(k^m)*(1*2*3...*m)*a 9 | =k^m*m!*a 10 | */ 11 | 12 | ll ncount(ll n, ll k) { 13 | ll cou = 0; 14 | while (n) cou += n /= k; 15 | return cou; 16 | } -------------------------------------------------------------------------------- /Mathematics/任意模数FFT+多项式取逆.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | typedef long long ll; 4 | const int maxn = 1e6 + 10; 5 | const int maxLen = 18, maxm = 1 << maxLen | 1; 6 | const ll maxv = 1e10 + 6; // 1e14, 1e15 7 | const long double pi = acos(-1.0); // double maybe is not enough 8 | ll mod, nlim, sp, msk; 9 | 10 | // 这个板子精度好像不行 ==! 11 | 12 | ll qpower(ll x, ll p) { // x ^ p % mod 13 | ll ret = 1; 14 | while (p) { 15 | if (p & 1) (ret *= x) %=mod; 16 | (x *= x) %=mod; 17 | p >>= 1; 18 | } 19 | return ret; 20 | } 21 | struct cp { 22 | long double r, i; 23 | cp() {} 24 | cp(long double r, long double i) : r(r), i(i) {} 25 | cp operator + (cp const &t) const { return cp(r + t.r, i + t.i); } 26 | cp operator - (cp const &t) const { return cp(r - t.r, i - t.i); } 27 | cp operator * (cp const &t) const { return cp(r * t.r - i * t.i, r * t.i + i * t.r); } 28 | cp conj() const { return cp(r, -i); } 29 | } w[maxm], wInv[maxm]; 30 | void init() { 31 | for(int i = 0, ilim = 1 << maxLen; i < ilim; ++i) { 32 | int j = i, k = ilim >> 1; // 2 pi / ilim 33 | for( ; !(j & 1) && !(k & 1); j >>= 1, k >>= 1); 34 | w[i] = cp((long double)cos(pi / k * j), (long double)sin(pi / k * j)); 35 | wInv[i] = w[i].conj(); 36 | } 37 | nlim = std::min(maxv / (mod - 1) / (mod - 1), maxn - 1LL); 38 | for(sp = 1; 1 << (sp << 1) < mod; ++sp); 39 | msk = (1 << sp) - 1; 40 | } 41 | 42 | void FFT(int n, cp a[], int flag) { 43 | static int bitLen = 0, bitRev[maxm] = {}; 44 | if(n != (1 << bitLen)) { 45 | for(bitLen = 0; 1 << bitLen < n; ++bitLen); 46 | for(int i = 1; i < n; ++i) 47 | bitRev[i] = (bitRev[i >> 1] >> 1) | ((i & 1) << (bitLen - 1)); 48 | } 49 | for(int i = 0; i < n; i ++) { 50 | if(i < bitRev[i]) { 51 | std::swap(a[i], a[bitRev[i]]); 52 | } 53 | } 54 | for(int i = 1, d = 1; d < n; ++i, d <<= 1) 55 | for(int j = 0; j < n; j += d << 1) 56 | for(int k = 0; k < d; ++k) { 57 | cp &AL = a[j + k], &AH = a[j + k + d]; 58 | cp TP = w[k << (maxLen - i)] * AH; 59 | AH = AL - TP, AL = AL + TP; 60 | } 61 | if(flag != -1) 62 | return; 63 | std::reverse(a + 1, a + n); 64 | for(int i = 0; i < n; ++i) { 65 | a[i].r /= n; 66 | a[i].i /= n; 67 | } 68 | } 69 | 70 | void polyMul(int a[], int aLen, int b[], int bLen, int c[]) // a 和 b 的卷积 c 71 | { // c not in {a, b} 72 | // std::cout << "mod = " << mod << '\n'; 73 | static cp A[maxm], B[maxm], C[maxm], D[maxm]; 74 | int len, cLen = aLen + bLen - 1; // optional: parameter 75 | for(len = 1; len < aLen + bLen - 1; len <<= 1); 76 | if(std::min(aLen, bLen) <= nlim) 77 | { 78 | for(int i = 0; i < len; i++) { 79 | A[i] = cp(i < aLen ? a[i] : 0, i < bLen ? b[i] : 0); 80 | } 81 | FFT(len, A, 1); 82 | cp tr(0, -0.25); 83 | for(int i = 0, j; i < len; i++) { 84 | j = (len - i) & (len - 1), B[i] = (A[i] * A[i] - (A[j] * A[j]).conj()) * tr; 85 | } 86 | FFT(len, B, -1); 87 | for(int i = 0; i < cLen; ++i) c[i] = (ll)(B[i].r + 0.5) % mod; 88 | return; 89 | } // if min(aLen, bLen) * mod <= maxv 90 | for(int i = 0; i < len; ++i) { 91 | A[i] = i < aLen ? cp(a[i] & msk, a[i] >> sp) : cp(0.0, 0.0); 92 | B[i] = i < bLen ? cp(b[i] & msk, b[i] >> sp) : cp(0.0, 0.0); 93 | } 94 | FFT(len, A, 1); 95 | FFT(len, B, 1); 96 | cp trL(0.5, 0.0), trH(0.0, -0.5), tr(0.0, 1.0); 97 | for(int i = 0, j; i < len; i++) { 98 | j = (len - i) & (len - 1); 99 | cp AL = (A[i] + A[j].conj()) * trL; 100 | cp AH = (A[i] - A[j].conj()) * trH; 101 | cp BL = (B[i] + B[j].conj()) * trL; 102 | cp BH = (B[i] - B[j].conj()) * trH; 103 | C[i] = AL * (BL + BH * tr); 104 | D[i] = AH * (BL + BH * tr); 105 | } 106 | FFT(len, C, -1); 107 | FFT(len, D, -1); 108 | for(int i = 0; i < cLen; ++i) 109 | { 110 | int v11 = (ll)(C[i].r + 0.5) % mod, v12 = (ll)(C[i].i + 0.5) % mod; 111 | int v21 = (ll)(D[i].r + 0.5) % mod, v22 = (ll)(D[i].i + 0.5) % mod; 112 | c[i] = (((((ll)v22 << sp) + v12 + v21) << sp) + v11) % mod; 113 | } 114 | } 115 | 116 | int c[maxm], tmp[maxm]; 117 | // y should clear to 0 118 | void polyInv(int x[], int y[], int deg) { // 多项式 x 求逆后的结果是 y 119 | if (deg == 1) { 120 | y[0] = qpower(x[0], mod - 2); 121 | return; 122 | } 123 | polyInv(x, y, (deg + 1) >> 1); 124 | 125 | copy(x, x + deg, tmp); 126 | int p = ((deg + 1) >> 1) + deg - 1; 127 | polyMul(y, (deg + 1) >> 1, tmp, deg, c); 128 | 129 | for (int i = 0; i < p; i += 1) c[i] = (- c[i] + mod) %mod; 130 | (c[0] += 2) %=mod; 131 | 132 | polyMul(y, (deg + 1) >> 1, c, deg, tmp); 133 | copy(tmp, tmp + deg, y); 134 | } 135 | 136 | int a[maxn],b[maxn]; 137 | int ans[maxn]; 138 | ll n,m; 139 | int main() 140 | { 141 | std::cin >> n >> m >> mod; 142 | for(int i = 0; i <= n; i++) { 143 | std::cin >> a[i]; 144 | } 145 | for(int i = 0; i <= m; i++) { 146 | std::cin >> b[i]; 147 | } 148 | init(); 149 | polyMul(a,n+1,b,m+1,ans); 150 | 151 | for(int i = 0; i <= n + m; i++) { 152 | std::cout << ans[i] << " "; 153 | } 154 | std::cout << '\n'; 155 | return 0; 156 | } 157 | -------------------------------------------------------------------------------- /Mathematics/康拓展开和逆康拓展开.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | typedef long long ll; 5 | const int N = 100 + 10; 6 | char s[N]; 7 | ll fact[N]; 8 | void init()//阶乘表,这里仅打表到20 9 | { 10 | fact[0] = 1; 11 | for(int i = 1; i <= 20; i++) fact[i] = i * fact[i-1]; 12 | } 13 | ll Cantor_expansion(char *s) 14 | { 15 | ll res = 0; 16 | int len = strlen(s); 17 | for(int i = 0; s[i]; i++) 18 | { 19 | int rnk = 0; 20 | for(int j = i+1; s[j]; j++) 21 | if(s[i] > s[j]) rnk++; 22 | res += rnk * fact[len-i-1]; 23 | } 24 | return res; 25 | } 26 | void Cantor_inverse_expansion(ll n, int m) 27 | {//n是在全排列中的名次,注意是从0开始计数的,若从1开始计数则要减去1。m是元素个数 28 | vector num; 29 | int arr[N], k = 0; 30 | for(int i = 1; i <= m; i++) num.push_back(i); 31 | for(int i = m; i >= 1; i--) 32 | { 33 | ll r = n % fact[i-1]; 34 | ll t = n / fact[i-1]; 35 | n = r; 36 | sort(num.begin(), num.end()); 37 | arr[k++] = num[t]; 38 | num.erase(num.begin() + t); 39 | } 40 | for(int i = 0; i < k; i++) printf("%d", arr[i]); 41 | printf("\n"); 42 | } 43 | int main() 44 | { 45 | init(); 46 | while(~ scanf("%s", s)) 47 | { 48 | int len = strlen(s); 49 | ll res = Cantor_expansion(s);//求出此排列的名次 50 | printf("%lld\n", res); 51 | Cantor_inverse_expansion(res, len);//根据排列的名次复原此排列 52 | } 53 | return 0; 54 | } -------------------------------------------------------------------------------- /Mathematics/快速乘.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: zhaoyang.liang 3 | * @Github: https://github.com/LzyRapx 4 | * @Date: 2019-10-21 22:52:09 5 | */ 6 | #include 7 | using namespace std; 8 | 9 | typedef long long ll; 10 | ll mul(ll A,ll B,ll mod) 11 | { 12 | return (A*B-(ll)((long double)A*B/mod)*mod+mod)%mod; 13 | } 14 | 15 | int main(int argc, char const *argv[]) 16 | { 17 | cout << mul(100000, 123, 10005) << endl; 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /Mathematics/快速幂.cpp: -------------------------------------------------------------------------------- 1 | 2 | //O(logb) 3 | typedef long long ll; 4 | ll qpower(ll a, ll b,ll mod) 5 | { 6 | long long ans=1; 7 | while(b>0) { 8 | if(b&1) ans=(ans*a)%mod; 9 | b>>=1; 10 | a=(a*a)%mod; 11 | } 12 | return ans; 13 | } -------------------------------------------------------------------------------- /Mathematics/杜教筛.cpp: -------------------------------------------------------------------------------- 1 | // #include 2 | // bzoj3944 3 | 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | typedef long long ll; 9 | const int maxn = 5000000; 10 | const int mod = 1e9+7; 11 | 12 | ll prime[maxn / 5]; 13 | 14 | ll phi[maxn]; 15 | ll mu[maxn]; 16 | 17 | // //计算[1, n]的phi值及mu值 18 | void linear_init(int N) 19 | { 20 | int tot = 0; 21 | memset(phi,-1,sizeof(phi)); 22 | memset(mu,-1,sizeof(mu)); 23 | phi[0] = mu[0] = 0; 24 | phi[1] = 1; 25 | mu[1] = 1; 26 | for(int i = 2; i < N; i++) { 27 | if(phi[i] < 0) { 28 | prime[tot++] = i; 29 | phi[i] = i - 1; 30 | mu[i] = -1; 31 | } 32 | for(int j = 0; j < tot && 1LL * i * prime[j] <= N; j++) { 33 | if(i % prime[j]) { 34 | phi[i * prime[j]] = phi[i] * (prime[j] - 1); 35 | mu[i * prime[j]] = - mu[i]; 36 | } 37 | else { 38 | phi[i * prime[j]] = phi[i] * prime[j]; 39 | mu[i * prime[j]] = 0; 40 | break; 41 | } 42 | } 43 | } 44 | // do something 45 | // for(int i = 2 ; i <= N; i++) { 46 | // phi[i] += phi[i-1]; 47 | // mu[i] += mu[i-1]; 48 | // } 49 | } 50 | std::map Mu,Phi; 51 | 52 | ll calc_phi(ll n) //phi的前缀和 53 | { 54 | if(n < maxn) return phi[n]; 55 | // std::map ::iterator it; 56 | // if ((it = Phi.find(n)) != Phi.end()) return it->second; 57 | if(Phi.count(n))return Phi[n]; 58 | ll ans = 0; 59 | ans = n * ( n + 1 ) >> 1; 60 | for(ll i = 2, last; i <= n; i = last + 1) { 61 | last = n / (n / i); 62 | ans -= (last - i + 1) * calc_phi(n / i); 63 | } 64 | return Phi[n] = ans; 65 | } 66 | ll calc_mu(ll n) // mu 的前缀和 67 | { 68 | if(n < maxn) return mu[n]; 69 | // std::map ::iterator it; 70 | // if ((it = Mu.find(n)) != Mu.end()) return it->second; 71 | if(Mu.count(n))return Mu[n]; 72 | ll ans = 1; 73 | for(ll i = 2, last; i <= n; i = last + 1) { 74 | last = n / (n / i); 75 | ans -= (last - i + 1) * calc_mu(n / i); 76 | } 77 | return Mu[n] = ans; 78 | } 79 | int main(int argc, char const *argv[]) { 80 | linear_init(5000000-1); 81 | int t; 82 | //std::cin >> t; 83 | scanf("%d", &t); 84 | int n; 85 | while (t--) { 86 | //std::cin >> n; 87 | scanf("%d", &n); 88 | //std::cout << calc_phi(n) << " " << calc_mu(n) << '\n'; 89 | printf("%lld %lld\n", calc_phi(n), calc_mu(n)); 90 | } 91 | 92 | return 0; 93 | } 94 | -------------------------------------------------------------------------------- /Mathematics/类欧几里得.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: zhaoyang.liang 3 | * @Github: https://github.com/LzyRapx 4 | * @Date: 2019-10-22 23:57:17 5 | */ 6 | 7 | // https://loj.ac/problem/138 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | typedef long long ll; 17 | #define maxn 100010 18 | #define mod 1000000007 19 | 20 | ll qpower(ll a, ll b) 21 | { 22 | ll ans = 1; 23 | while(b > 0) { 24 | if(b & 1) ans = (ans * a) % mod; 25 | b >>= 1; 26 | a = (a * a) % mod; 27 | } 28 | return ans; 29 | } 30 | inline int mul(int a, int b) { return 1ll * a * b % mod; } 31 | // head 32 | int C[21][21]; 33 | int tr[21][21]; 34 | vector mn(vector p) { 35 | //差分,返回p(x) - p(x - 1) 36 | int n = p.size(); 37 | if (n == 1) return vector{1, 0}; 38 | vector fn(n - 1); 39 | for (int i = 0; i < n; i++) 40 | for (int j = 0; j < i; j++) { 41 | int nr = mul(p[i], C[i][j]); 42 | if ((i - j) % 2 == 0) nr *= -1; 43 | fn[j] = (fn[j] + nr) % mod; 44 | } 45 | return fn; 46 | } 47 | int cal(vector p, int c) { 48 | //计算c带入p的值 49 | int mt = 1, ans = 0; 50 | for (int j = 0; j < p.size(); j++) { 51 | ans = (ans + mul(p[j], mt)) % mod; 52 | mt = mul(mt, c); 53 | } 54 | return ans; 55 | } 56 | void init() { 57 | //计算组合数及前缀和系数 58 | for (int i = 0; i < 20; i++) 59 | for (int j = 0; j <= i; j++) { 60 | if (i == j || j == 0) 61 | C[i][j] = 1; 62 | else 63 | C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod; 64 | } 65 | 66 | for (int i = 0; i < 20; i++) { 67 | int bk = qpower(i + 1, mod - 2); 68 | tr[i][i + 1] = bk; 69 | vector u(i + 2); 70 | u[i + 1] = bk; 71 | u = mn(u); 72 | for (int j = i - 1; j >= 0; j--) 73 | for (int q = 0; q <= j + 1; q++) 74 | tr[i][q] = (tr[i][q] - mul(u[j], tr[j][q])) % mod; 75 | } 76 | } 77 | const int mxs = 10; 78 | struct res { 79 | int a[mxs + 1][mxs + 1]; 80 | res() { memset(a, 0, sizeof(a)); } 81 | int cal(vector& p, vector& q) { 82 | int ans = 0; 83 | for (int j = 0; j < p.size(); j++) 84 | for (int k = 0; k < q.size(); k++) 85 | ans = (ans + mul(mul(p[j], q[k]), a[j][k])) % mod; 86 | return ans; 87 | } 88 | }; 89 | res cal(int n, int a, int b, int c) { 90 | // 1 到 n 91 | if (n == 0) return res(); 92 | int ux = a / c, uy = b / c; 93 | a %= c, b %= c; 94 | if (b < 0) uy--, b += c; 95 | res q1, q2, q3; 96 | if (a) q1 = cal((1ll * n * a + b) / c, c, -(b + 1), a); 97 | for (int j = 0; j <= mxs; j++) { 98 | for (int k = 0; k + j <= mxs; k++) { 99 | vector p(j + 2); 100 | for (int r = 0; r <= j + 1; r++) p[r] = tr[j][r]; 101 | vector q(k); 102 | for (int l = 0; l < k; l++) { 103 | q[l] = C[k][l]; 104 | if ((k - l) % 2 == 0) q[l] *= -1; 105 | } 106 | if (k == 0) 107 | q2.a[j][k] = cal(p, n); 108 | else { 109 | p[0] = (p[0] - cal(p, n)) % mod; 110 | for (int j = 0; j < p.size(); j++) p[j] = -p[j]; 111 | q2.a[j][k] = q1.cal(q, p); 112 | } 113 | } 114 | } 115 | for (int j = 0; j <= mxs; j++) 116 | for (int k = 0; k + j <= mxs; k++) { 117 | int l0 = 1; 118 | for (int l = 0; l <= k; l++) { 119 | int l1 = 1; 120 | for (int m = 0; m <= k - l; m++) { 121 | int nans = mul(l0, l1); 122 | nans = mul(nans, C[k][l] * C[k - l][m]); 123 | nans = mul(nans, q2.a[j + l][k - l - m]); 124 | q3.a[j][k] = (q3.a[j][k] + nans) % mod; 125 | l1 = mul(l1, uy); 126 | } 127 | l0 = mul(l0, ux); 128 | } 129 | } 130 | return q3; 131 | } 132 | 133 | int brt(int n, int a, int b, int c, int k1, int k2) { 134 | ll ans = 0; 135 | for (int j = 1; j <= n; j++) { 136 | ll x = j, y = (1ll * a * j + b) / c; 137 | y %= mod; 138 | ans += qpower(x, k1) * qpower(y, k2); 139 | ans %= mod; 140 | } 141 | return ans; 142 | } 143 | int main() { 144 | init(); 145 | int t; 146 | cin >> t; 147 | for (int i = 0; i < t; i++) { 148 | int n, a, b, c, k1, k2; 149 | cin >> n >> a >> b >> c >> k1 >> k2; 150 | // int tr = brt(n, a, b, c, k1, k2); 151 | res ans = cal(n, a, b, c); 152 | int fn = ans.a[k1][k2]; 153 | if (k1 == 0) fn += qpower(b / c, k2), fn %= mod; 154 | if (fn < 0) fn += mod; 155 | cout << fn << endl; 156 | } 157 | return 0; 158 | } -------------------------------------------------------------------------------- /Mathematics/线性筛prime+phi+mu.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 贾志鹏线性筛: 3 | 4 | 功能:预处理素数prime,欧拉函数phi,莫比乌斯函数mu。 5 | 6 | 复杂度:O(n) 7 | 8 | */ 9 | 10 | //#include 11 | #include 12 | #include 13 | #include 14 | using namespace std; 15 | typedef long long ll; 16 | const int maxn = 3000000; 17 | const int mod = 1e9+7; 18 | 19 | ll isprime[maxn]; 20 | ll prime[maxn]; 21 | 22 | ll phi[maxn]; 23 | ll mu[maxn]; 24 | 25 | void linear_init(int N) 26 | { 27 | int tot = 0; 28 | memset(isprime,0,sizeof(isprime)); 29 | memset(phi,-1,sizeof(phi)); 30 | memset(mu,-1,sizeof(mu)); 31 | phi[0] = mu[0] = 0; 32 | phi[1] = 1; 33 | mu[1] = 1; 34 | for(int i = 2; i < N; i++) { 35 | if(phi[i] < 0) { 36 | prime[tot++] = i; 37 | phi[i] = i - 1; 38 | mu[i] = -1; 39 | } 40 | for(int j = 0; j < tot && 1LL * i * prime[j] <= N; j++) { 41 | if(i % prime[j]) { 42 | phi[i * prime[j]] = phi[i] * (prime[j] - 1); 43 | mu[i * prime[j]] = - mu[i]; 44 | } 45 | else { 46 | phi[i * prime[j]] = phi[i] * prime[j]; 47 | mu[i * prime[j]] = 0; 48 | break; 49 | } 50 | } 51 | } 52 | //do something 53 | } 54 | int main(int argc, char const *argv[]) { 55 | linear_init(1000000); 56 | for(int i=0;i<=5;i++) { 57 | std::cout << prime[i] <<" " << phi[i] <<" " << mu[i]<< '\n'; 58 | } 59 | 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /Others/README.md: -------------------------------------------------------------------------------- 1 | ### TODO 2 | -------------------------------------------------------------------------------- /Skill Trees.txt: -------------------------------------------------------------------------------- 1 | 3. 平衡树 2 | Treap 随机平衡二叉树 3 | Splay 伸展树 4 | * Scapegoat Tree 替罪羊树 5 | 6 | 4. 块状数组,块状链表 7 | 8 | 5.* 树套树 9 | 线段树套线段树 10 | 线段树套平衡树 11 | * 平衡树套线段树 12 | 13 | 6.可并堆 14 | 15 | 左偏树 16 | 17 | *配对堆 18 | 19 | 7. *KDtree,*四分树 20 | 21 | 2. * 可持久化平衡树 22 | 23 | 3. * 可持久化块状数组 24 | 25 | 1.5 字符串相关算法及数据结构 26 | 27 | 2. AC 自动机 28 | 29 | 3. 后缀数组 30 | 31 | 4. *后缀树 32 | 33 | 5. *后缀自动机 34 | 35 | 6. 字典树 Trie 36 | 37 | 7. manacher 38 | 39 | 1.6 图论相关 40 | 41 | 2. 最短路,次短路,K短路 42 | 43 | 3. 图的连通 44 | 45 | 连通分量 46 | 47 | 割点,割边 48 | 49 | 4. 网络流 50 | 51 | 分数规划 52 | 53 | 5. 树相关 54 | 55 | 树的分治算法(点分治,边分治,*动态?树分治) 56 | 57 | 动态树 (LCT,*树分块) 58 | 59 | 虚树 60 | 61 | *prufer编码 62 | 63 | 9. 二分图 64 | *KM算法 65 | 匈牙利算法 66 | 67 | 8. 博弈论:树上删边游戏 68 | 69 | 9. *拉格朗日乘子法 70 | 71 | 11. 线性规划与网络流 72 | 73 | 12. 单纯型线性规划 74 | 75 | 13. 辛普森积分 76 | 77 | 14. 模线性方程组 78 | 79 | 15. 容斥原理与莫比乌斯反演 80 | 81 | 16. 置换群 82 | 83 | 17. 快速傅里叶变换 84 | 85 | 18. *大步小步法(BSGS),扩展BSGS 86 | 87 | 1.8 动态规划 88 | 89 | 1. 一般,背包,状压,区间,环形,树形,数位动态规划 90 | 91 | 记忆化搜索 92 | 93 | 斯坦纳树 94 | 95 | 背包九讲 96 | 97 | 2. 斜率优化与* 四边形不等式优化 98 | 99 | 3. 环 + 外向树上的动态规划 100 | 101 | 4. *插头动态规划 102 | 103 | 1.9 计算几何 104 | 105 | 1. 计算几何基础 106 | 107 | 2. 三维计算几何初步 108 | 109 | 3. *梯形剖分与*三角形剖分 110 | 111 | 4. 旋转卡壳 112 | 113 | 5. 半平面交 114 | 115 | 7. 扫描线 116 | 117 | 1.11 特殊算法 118 | 119 | 1. 莫队算法,*树上莫队 120 | 121 | 2. 模拟退火 122 | 123 | 3. 爬山算法 124 | 125 | 4. 随机增量法 126 | 127 | 1.12 其它重要工具与方法 128 | 129 | 1.模拟与贪心 130 | 131 | 2. 二分,三分法(求偏导) 132 | 133 | 3. 分治,CDQ分治 134 | 135 | 6. ST表 136 | 137 | 1.13 STL 138 | 139 | 5. rope 140 | 141 | 1.14 非常见算法 142 | 1. *朱刘算法 143 | 2. *弦图与区间图 144 | -------------------------------------------------------------------------------- /String/AC自动机.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: zhaoyang.liang 3 | * @Github: https://github.com/LzyRapx 4 | * @Date: 2020-02-21 21:25:47 5 | */ 6 | // E(n) be the nth positive eleven-free integer. 7 | // find E(1e18) 8 | // Aho-Corasick automaton 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace std; 16 | typedef long long ll; 17 | 18 | const int maxn = 1e4; 19 | int trie[maxn][10]; 20 | int cntword[maxn]; // 记录该单词出现次数 21 | int fail[maxn]; 22 | int cnt = 0; 23 | long long dp[20][maxn]; 24 | 25 | void insertWords(string s){ 26 | int root = 0; 27 | for(int i = 0;i < s.size();i++){ 28 | int next = s[i] - '0'; 29 | if(!trie[root][next]) { 30 | memset(trie[cnt],0,sizeof(trie[cnt])); 31 | trie[root][next] = ++cnt; 32 | } 33 | root = trie[root][next]; 34 | } 35 | cntword[root]++; 36 | } 37 | void getFail(){ 38 | queueq; 39 | for(int i = 0;i <= 9; i++){ 40 | if(trie[0][i]){ 41 | fail[trie[0][i]] = 0; 42 | q.push(trie[0][i]); 43 | } 44 | } 45 | while(!q.empty()){ 46 | int now = q.front(); 47 | q.pop(); 48 | for(int i = 0;i <= 9; i++) { 49 | if(trie[now][i]) { 50 | fail[trie[now][i]] = trie[fail[now]][i]; 51 | if(cntword[fail[trie[now][i]]]) { 52 | ++cntword[trie[now][i]]; 53 | } 54 | q.push(trie[now][i]); 55 | } 56 | else { 57 | trie[now][i] = trie[fail[now]][i]; 58 | } 59 | } 60 | } 61 | } 62 | int query(string s) { 63 | int now = 0,ans = 0; 64 | for(int i = 0; i < s.size(); i++){ 65 | now = trie[now][s[i] - '0']; 66 | for(int j = now; j > 0 && cntword[j] != -1; j = fail[j]){ 67 | ans += cntword[j]; 68 | cntword[j] = -1; 69 | } 70 | } 71 | return ans; 72 | } 73 | int digit[maxn]; 74 | ll dfs(int dep,int state, bool ending) 75 | { 76 | if(dep <= -1) return cntword[state] == 0; 77 | if(ending == 0 && dp[dep][state] != -1) return dp[dep][state]; 78 | int End = ending ? digit[dep] : 9; 79 | ll ans = 0; 80 | for(int i = 0; i <= End; i++) 81 | { 82 | if(cntword[trie[state][i]]) continue; 83 | ans += dfs(dep-1, trie[state][i],ending && i == End); 84 | } 85 | if(ending == 0) dp[dep][state] = ans; 86 | return ans; 87 | } 88 | ll calc(ll x) { 89 | if(x == 0) return 0; 90 | int len = 0; 91 | while(x > 0) 92 | { 93 | digit[len++]= x % 10; 94 | x /= 10; 95 | } 96 | return dfs(len - 1, 0, 1) - 1; 97 | } 98 | int main() { 99 | ll N; 100 | cin >> N; 101 | memset(dp, -1, sizeof(dp)); 102 | memset(trie, 0, sizeof(trie)); 103 | memset(fail, -1, sizeof(fail)); 104 | memset(cntword, 0, sizeof(cntword)); 105 | ll ans = 1; 106 | // string s = ""; 107 | while(ans <= N / 11) 108 | { 109 | ans *= 11; 110 | int cnt = 0; 111 | string s = ""; 112 | ll tmp = ans; 113 | while(tmp > 0) 114 | { 115 | s = s + to_string(tmp % 10); 116 | cnt++; 117 | tmp /= 10; 118 | } 119 | for(int i = 0; i < cnt / 2; i++) { 120 | swap(s[i], s[cnt - 1 - i]); 121 | } 122 | // cout << "cnt = " << cnt << endl; 123 | // cout << "s = " << s << endl; 124 | insertWords(s); 125 | } 126 | getFail(); 127 | calc(N * 9); 128 | 129 | ll l = N, r = 8 * N; 130 | while(l < r) { 131 | ll mid = (l + r) / 2; 132 | ll ans = calc(mid); 133 | if(ans < N) { 134 | l = mid + 1; 135 | } 136 | else { 137 | r = mid; 138 | } 139 | } 140 | cout << l << endl; 141 | // ans = 1295552661530920149 142 | return 0; 143 | } -------------------------------------------------------------------------------- /String/AhoCorasick.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | const int maxn = 500100; 4 | 5 | // AC自动机有三个部分,分别是建树,获取失配指针和查询。 6 | // Aho_Corasick_Automaton :可以简单的理解为将KMP放在Trie树上 7 | // https://www.luogu.org/problemnew/show/P3808 8 | // AC自动机模板 9 | 10 | int End[maxn]; 11 | int ch[maxn][26]; 12 | int fail[maxn]; 13 | int sz; 14 | void insert(string s) { 15 | int now = 0; //字典树的当前指针 16 | for (int i = 0; i < (int)s.size(); i++) { 17 | int c = s[i] - 'a'; 18 | // Trie树没有这个子节点 : 就构造出来 19 | if (!ch[now][c]) ch[now][c] = ++sz; 20 | now = ch[now][c]; //然后向下构造 21 | } 22 | End[now]++; //标记单词结尾 23 | } 24 | void getfail() //构造fail指针 25 | { 26 | queue que; 27 | for (int i = 0; i < 26; i++) { 28 | if (ch[0][i]) { 29 | que.push(ch[0][i]); 30 | fail[ch[0][i]] = 0; //指向根节点 31 | } 32 | } 33 | while (!que.empty()) { // BFS求fail指针 34 | int u = que.front(); 35 | que.pop(); 36 | for (int i = 0; i < 26; i++) { //枚举所有子节点 37 | int v = ch[u][i]; 38 | if (v) { //存在这个子节点 39 | //子节点的 fail指针指向当前节点的 fail指针所指向的节点的相同子节点 40 | fail[v] = ch[fail[u]][i]; 41 | que.push(v); 42 | } 43 | // 不存在这个子节点 44 | // 当前节点的这个子节点指向当前节点fail指针的这个子节点 45 | else 46 | ch[u][i] = ch[fail[u]][i]; 47 | } 48 | } 49 | } 50 | int Count(string s) { 51 | int now = 0; 52 | int ans = 0; 53 | for (int i = 0; i < (int)s.size(); i++) { 54 | now = ch[now][s[i] - 'a']; //向下一层 55 | for (int j = now; j && End[j] != -1; j = fail[j]) { 56 | ans += End[j]; 57 | End[j] = -1; 58 | } 59 | } 60 | return ans; 61 | } 62 | string s; 63 | int main(int argc, char const *argv[]) { 64 | int n; 65 | std::cin >> n; 66 | for (int i = 1; i <= n; i++) { 67 | std::cin >> s; 68 | insert(s); 69 | } 70 | getfail(); 71 | std::cin >> s; 72 | int ans = Count(s); 73 | std::cout << ans << '\n'; 74 | return 0; 75 | } 76 | -------------------------------------------------------------------------------- /String/EX_KMP.cpp: -------------------------------------------------------------------------------- 1 | // 扩展KMP的应用: 2 | 3 | // 给出模板串S和串T,长度分别为Slen和Tlen,要求在线性时间内,对于每个S[i](0<=i 13 | using namespace std; 14 | const int N = 101010; 15 | int next[N], extand[N]; 16 | void getnext(char *T) { // next[i]: 以第i位置开始的子串 与 T的公共前缀 17 | int i, length = strlen(T); 18 | next[0] = length; 19 | for (i = 0; i < length - 1 && T[i] == T[i + 1]; i++) 20 | ; 21 | next[1] = i; 22 | int a = 1; 23 | for (int k = 2; k < length; k++) { 24 | int p = a + next[a] - 1, L = next[k - a]; 25 | if ((k - 1) + L >= p) { 26 | int j = (p - k + 1) > 0 ? (p - k + 1) : 0; 27 | while (k + j < length && T[k + j] == T[j]) 28 | j++; // 枚举(p+1,length) 与(p-k+1,length) 区间比较 29 | next[k] = j, a = k; 30 | } else 31 | next[k] = L; 32 | } 33 | } 34 | void getextand(char *S, char *T) { 35 | memset(next, 0, sizeof(next)); 36 | getnext(T); 37 | int Slen = strlen(S), Tlen = strlen(T), a = 0; 38 | int MinLen = Slen > Tlen ? Tlen : Slen; 39 | while (a < MinLen && S[a] == T[a]) a++; 40 | extand[0] = a, a = 0; 41 | for (int k = 1; k < Slen; k++) { 42 | int p = a + extand[a] - 1, L = next[k - a]; 43 | if ((k - 1) + L >= p) { 44 | int j = (p - k + 1) > 0 ? (p - k + 1) : 0; 45 | while (k + j < Slen && j < Tlen && S[k + j] == T[j]) j++; 46 | extand[k] = j; 47 | a = k; 48 | } else 49 | extand[k] = L; 50 | } 51 | } 52 | 53 | int main() { 54 | char s[N], t[N]; 55 | while (~scanf("%s %s", s, t)) { 56 | getextand(s, t); 57 | for (int i = 0; i < strlen(t); i++) printf("%d ", next[i]); 58 | puts(""); 59 | for (int i = 0; i < strlen(s); i++) printf("%d ", extand[i]); 60 | puts(""); 61 | } 62 | } 63 | /* 64 | aaaabaaa aaaa 65 | */ -------------------------------------------------------------------------------- /String/KMP(含注释).cpp: -------------------------------------------------------------------------------- 1 | // https://loj.ac/problem/103 2 | // res表示 B 在 A 中的出现次数。 3 | // fail就是next数组 4 | int kmp(char *a, char *b) // 在 a 中寻找 b 5 | { 6 | // 求出字符串长度 7 | int na = strlen(a + 1), nb = strlen(b + 1); 8 | static int fail[MAXN + 1]; 9 | 10 | fail[1] = 0; 11 | for (int i = 2; i <= nb; i++) { 12 | // 取上一位置的 fail 位置之后的字符,判断是否和该位相同 13 | int j = fail[i - 1]; 14 | // 不断地向前找 fail 位置,直到找到 0 位置或可以匹配当前字符 15 | while (j != 0 && b[j + 1] != b[i]) j = fail[j]; 16 | 17 | // 如果能匹配,设置当前位置的 fail 位置 18 | if (b[j + 1] == b[i]) 19 | fail[i] = j + 1; 20 | else 21 | fail[i] = 0; // 找不到匹配位置 22 | } 23 | 24 | int res = 0; // 匹配次数 25 | for (int i = 1, j = 0; i <= na; i++) { 26 | // 取上一位置的 fail 位置之后的字符,判断是否和要匹配的字符相同 27 | while (j != 0 && b[j + 1] != a[i]) j = fail[j]; 28 | 29 | // 这一位可以匹配上 30 | if (b[j + 1] == a[i]) j++; 31 | 32 | // 匹配成功 33 | if (j == nb) { 34 | res++; 35 | j = fail[j]; // 为了能匹配重叠串 36 | // j = 0; // 如果不允许重叠匹配 37 | } 38 | } 39 | 40 | return res; 41 | } -------------------------------------------------------------------------------- /String/KMP.cpp: -------------------------------------------------------------------------------- 1 | //可重叠 2 | #include 3 | #include 4 | void makeNext(const char P[], int next[]) { 5 | int q, k; 6 | int m = strlen(P); 7 | next[0] = 0; 8 | for (q = 1, k = 0; q < m; ++q) { 9 | while (k > 0 && P[q] != P[k]) k = next[k - 1]; 10 | if (P[q] == P[k]) { 11 | k++; 12 | } 13 | next[q] = k; 14 | } 15 | } 16 | int kmp(const char T[], const char P[], int next[]) { 17 | int n, m; 18 | int i, q; 19 | n = strlen(T); 20 | m = strlen(P); 21 | makeNext(P, next); 22 | for (i = 0, q = 0; i < n; ++i) { 23 | while (q > 0 && P[q] != T[i]) q = next[q - 1]; 24 | if (P[q] == T[i]) { 25 | q++; 26 | } 27 | if (q == m) { 28 | printf("Pattern occurs with shift:%d\n", (i - m + 1)); 29 | // q=0; 30 | } 31 | } 32 | } 33 | int main() { 34 | int i; 35 | int next[20] = {0}; 36 | // char T[] = "ababxbababcadfdsss"; 37 | // char P[] = "abcdabd"; 38 | char T[] = "ababababa"; 39 | char P[] = "aba"; 40 | printf("%s\n", T); 41 | printf("%s\n", P); 42 | // makeNext(P,next); 43 | kmp(T, P, next); 44 | for (i = 0; i < strlen(P); ++i) { 45 | printf("%d ", next[i]); 46 | } 47 | printf("\n"); 48 | return 0; 49 | } 50 | /* 51 | //不可重叠 52 | #include 53 | #include 54 | void makeNext(const char P[],int next[]) 55 | { 56 | int q,k; 57 | int m = strlen(P); 58 | next[0] = 0; 59 | for (q = 1,k = 0; q < m; ++q) 60 | { 61 | while(k > 0 && P[q] != P[k]) 62 | k = next[k-1]; 63 | if (P[q] == P[k]) 64 | { 65 | k++; 66 | } 67 | next[q] = k; 68 | } 69 | } 70 | int kmp(const char T[],const char P[],int next[]) 71 | { 72 | int n,m; 73 | int i,q; 74 | n = strlen(T); 75 | m = strlen(P); 76 | makeNext(P,next); 77 | for (i = 0,q = 0; i < n; ++i) 78 | { 79 | while(q > 0 && P[q] != T[i]) 80 | q = next[q-1]; 81 | if (P[q] == T[i]) 82 | { 83 | q++; 84 | 85 | } 86 | if (q == m) 87 | { 88 | printf("Pattern occurs with shift:%d\n",(i-m+1)); 89 | q = 0; 90 | } 91 | } 92 | } 93 | int main() 94 | { 95 | int i; 96 | int next[20]={0}; 97 | char T[] = "ababababa"; 98 | char P[] = "aba"; 99 | printf("%s\n",T); 100 | printf("%s\n",P ); 101 | // makeNext(P,next); 102 | kmp(T,P,next); 103 | for (i = 0; i < strlen(P); ++i) 104 | { 105 | printf("%d ",next[i]); 106 | } 107 | printf("\n"); 108 | return 0; 109 | } 110 | */ -------------------------------------------------------------------------------- /String/LIS.cpp: -------------------------------------------------------------------------------- 1 | // n*logn 2 | scanf("%d", &T); 3 | for (int kase = 1; kase <= T; kase++) { 4 | scanf("%d", &n); 5 | for (int i = 1; i <= n; i++) scanf("%d", &a[i]); 6 | 7 | b[1] = a[1]; 8 | len = 1; 9 | for (int i = 2; i <= n; i++) 10 | if (a[i] > b[len]) 11 | b[++len] = a[i]; 12 | else { 13 | int pos = lower_bound(b + 1, b + 1 + len, a[i]) - b; 14 | b[pos] = a[i]; 15 | } 16 | printf("%d\n", len); 17 | } -------------------------------------------------------------------------------- /String/Manacher.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Manacher 求最长回文串 O(n) 3 | getstr预处理: abc -> $#a#b#c# 4 | len=strlen(s) , n=2*len+2 5 | p[i]为str[]第i个字符为中心的回文串长度+1 6 | */ 7 | 8 | char str[N << 1], s[N]; 9 | int p[N << 1]; 10 | int n, len; 11 | 12 | void Manacher(char str[], int p[]) { 13 | int id, mx; 14 | id = 1, mx = 1; 15 | p[0] = p[1] = 1; 16 | int j; 17 | for (int i = 2; i < n; i++) { 18 | p[i] = 1; 19 | if (mx > i) { 20 | p[i] = min(p[(id << 1) - i], mx - i); 21 | } 22 | while (str[i + p[i]] == str[i - p[i]]) p[i]++; 23 | if (i + p[i] > mx) { 24 | id = i; 25 | mx = i + p[i]; 26 | } 27 | } 28 | } 29 | 30 | void getstr() { 31 | str[0] = '$'; 32 | str[n] = '#'; 33 | str[n + 1] = '\0'; 34 | for (int i = len * 2; i >= 1; --i) { 35 | if (i & 1) 36 | str[i] = '#'; 37 | else 38 | str[i] = str[i / 2]; 39 | } 40 | } -------------------------------------------------------------------------------- /String/SA.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #define LL long long 15 | #define ULL unsigned long long 16 | using namespace std; 17 | const int MAXN = 100010; 18 | //以下为倍增算法求后缀数组 19 | int wa[MAXN], wb[MAXN], wv[MAXN], Ws[MAXN]; 20 | 21 | // 由于末尾填了0,所以如果r[a]==r[b](实际是y[a]==y[b]), 22 | // 说明待合并的两个长为j的字符串,前面那个一定不包含末尾0, 23 | // 因而后面这个的起始位置至多在0的位置,不会再靠后了,因而不会产生数组越界。 24 | int cmp(int *r, int a, int b, int l) { 25 | return r[a] == r[b] && r[a + l] == r[b + l]; 26 | } 27 | 28 | /* 29 | Da倍增算法实现 30 | 输入:字符串数组r,后缀数组SA初始化,长度n 31 | m代表字符串中字符的取值范围,是基数排序的基数范围,字母可以直接取128 32 | 如果原序列本身都是整数的话,则m可以取比最大的整数大1的值。 33 | 输出:无 34 | */ 35 | /**< 传入参数:str,sa,len+1,ASCII_MAX+1 */ 36 | void da(const char *r, int *sa, int n, int m) // Doubling Algorithm 37 | { 38 | int i, j, p, *x = wa, *y = wb, *t; 39 | 40 | // 前四个for先对字符串首字符进行一次基数排序,得到排序后的SA 41 | for (i = 0; i < m; i++) Ws[i] = 0; 42 | for (i = 0; i < n; i++) Ws[x[i] = r[i]]++; 43 | for (i = 1; i < m; i++) Ws[i] += Ws[i - 1]; 44 | for (i = n - 1; i >= 0; i--) sa[--Ws[x[i]]] = i; 45 | // 下面for循环主要实现了倍增算法的内容,j从长度1开始一直递增 46 | // 每次倍数增加,也是每次带合并的字符串的长度值。p是每次rank时 47 | // 所不需要的数量,当p和n相同时说明已经排序结束了。m是基数排序 48 | // 所需要的取值range。 49 | for (j = 1, p = 1; p < n; j *= 2, m = p) { 50 | // 下面两个for是对第二个关键字进行排序 51 | for (p = 0, i = n - j; i < n; i++) 52 | y[p++] = i; //当长度为j时,n-j开始的后缀串都没有第二个关键字 53 | //那么这些字符串的第二个关键字都是补齐的最小字符,按照第二关键字排序后 54 | // 这些字符串都将排在最前面。 55 | for (i = 0; i < n; i++) 56 | if (sa[i] >= j) 57 | y[p++] = 58 | sa[i] - 59 | j; // 这里将有第二关键字的后缀进行排序y[]里存放的是按第二关键字排序的字符串下标 60 | for (i = 0; i < n; i++) wv[i] = x[y[i]]; 61 | // 下面四行便是对后缀的第一关键字进行基数排序 62 | for (i = 0; i < m; i++) Ws[i] = 0; 63 | for (i = 0; i < n; i++) Ws[wv[i]]++; 64 | for (i = 1; i < m; i++) Ws[i] += Ws[i - 1]; 65 | for (i = n - 1; i >= 0; i--) sa[--Ws[wv[i]]] = y[i]; 66 | // 下面就是计算合并之后的rank值了,用x[]存储计算出的各字符串rank的值 67 | // 要注意的是但计算rank的时候必须让相同的字符串有相同的rank,要不然p==n之后就结束了。 68 | for (t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; i++) 69 | x[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? p - 1 : p++; 70 | } 71 | return; 72 | } 73 | int sa[MAXN], Rank[MAXN], height[MAXN]; 74 | //求height数组 75 | /**< str,sa,len */ 76 | void calheight(const char *r, int *sa, int n) { 77 | int i, j, k = 0; 78 | for (i = 1; i <= n; i++) Rank[sa[i]] = i; 79 | for (i = 0; i < n; height[Rank[i++]] = k) 80 | for (k ? k-- : 0, j = sa[Rank[i] - 1]; r[i + k] == r[j + k]; k++) 81 | ; 82 | // Unified 83 | for (int i = n; i >= 1; --i) ++sa[i], Rank[i] = Rank[i - 1]; 84 | } 85 | 86 | char str[MAXN]; 87 | int main() { 88 | while (scanf("%s", str) != EOF) { 89 | int len = strlen(str); 90 | da(str, sa, len + 1, 130); 91 | calheight(str, sa, len); 92 | puts("--------------All Suffix--------------"); 93 | for (int i = 1; i <= len; ++i) { 94 | printf("%d:\t", i); 95 | for (int j = i - 1; j < len; ++j) printf("%c", str[j]); 96 | puts(""); 97 | } 98 | puts(""); 99 | puts("-------------After sort---------------"); 100 | for (int i = 1; i <= len; ++i) { 101 | printf("sa[%2d ] = %2d\t", i, sa[i]); 102 | for (int j = sa[i] - 1; j < len; ++j) printf("%c", str[j]); 103 | puts(""); 104 | } 105 | puts(""); 106 | puts("---------------Height-----------------"); 107 | for (int i = 1; i <= len; ++i) printf("height[%2d ]=%2d \n", i, height[i]); 108 | puts(""); 109 | puts("----------------Rank------------------"); 110 | for (int i = 1; i <= len; ++i) printf("Rank[%2d ] = %2d\n", i, Rank[i]); 111 | puts("------------------END-----------------"); 112 | } 113 | return 0; 114 | } -------------------------------------------------------------------------------- /String/manacher (2).cpp: -------------------------------------------------------------------------------- 1 | // 处理出一个字符串的所有回文子串。 2 | const int N = 1e6 + 100; 3 | char tmp[2 * N]; 4 | int r[2 * N]; 5 | int manacher(char *s) { 6 | int len = strlen(s); 7 | for (int i = 0; i < len; i++) { 8 | tmp[2 * i + 1] = '#'; 9 | tmp[2 * i + 2] = s[i]; 10 | } 11 | tmp[0] = '@'; 12 | tmp[2 * len + 1] = '#'; 13 | tmp[2 * len + 2] = '\0'; 14 | len = 2 * len + 2; 15 | // printf("%s\n", tmp); 16 | int id, mx = 0, ret = 0; 17 | for (int i = 0; i < len; i++) { 18 | r[i] = i < mx ? Min(r[2 * id - i], mx - i) : 1; 19 | while (tmp[i + r[i]] == tmp[i - r[i]]) r[i]++; 20 | if (r[i] + i > mx) { 21 | mx = r[i] + i; 22 | id = i; 23 | } 24 | ret = Max(ret, r[i]); 25 | } 26 | // for (int i = 0; i < 2 * len + 1; i++) { 27 | // printf("%d ", r[i]); 28 | // } 29 | return ret - 1; 30 | } -------------------------------------------------------------------------------- /String/multi - String Hash.cpp: -------------------------------------------------------------------------------- 1 | /* String Hash 2 | -BKDRHash建议使用longlong,发生冲突概率很小,如果还是有冲突,那么用两个hash 3 | 4 | Hash函数 数据1 数据2 数据3 数据4 数据1得分 5 | 数据2得分 数据3得分 数据4得分 平均分 6 | BKDRHash 2 0 4774 481 96.55 100 90.95 82.05 92.64 7 | APHash 2 3 4754 493 96.55 88.46 100 51.28 86.28 8 | DJBHash 2 2 4975 474 96.55 92.31 0 100 83.43 9 | JSHash 1 4 4761 506 100 84.62 96.83 17.95 81.94 10 | RSHash 1 0 4861 505 100 100 51.58 20.51 75.96 11 | SDBMHash 3 2 4849 504 93.1 92.31 57.01 23.08 72.41 12 | PJWHash 30 26 4878 513 0 0 43.89 0 21.95 13 | ELFHash 30 26 4878 513 0 0 43.89 0 21.95 14 | */ 15 | 16 | // BKDR Hash Function 17 | unsigned int BKDRHash(char *str) { 18 | unsigned int seed = 131; // 31 131 1313 13131 131313 etc.. 19 | unsigned int hash = 0; 20 | 21 | while (*str) { 22 | hash = hash * seed + (*str++); 23 | } 24 | 25 | return (hash & 0x7FFFFFFF); 26 | } 27 | 28 | // SDBMHash 29 | unsigned int SDBMHash(char *str) { 30 | unsigned int hash = 0; 31 | 32 | while (*str) { 33 | // equivalent to: hash = 65599*hash + (*str++); 34 | hash = (*str++) + (hash << 6) + (hash << 16) - hash; 35 | } 36 | 37 | return (hash & 0x7FFFFFFF); 38 | } 39 | 40 | // RS Hash Function 41 | unsigned int RSHash(char *str) { 42 | unsigned int b = 378551; 43 | unsigned int a = 63689; 44 | unsigned int hash = 0; 45 | 46 | while (*str) { 47 | hash = hash * a + (*str++); 48 | a *= b; 49 | } 50 | 51 | return (hash & 0x7FFFFFFF); 52 | } 53 | 54 | // JS Hash Function 55 | unsigned int JSHash(char *str) { 56 | unsigned int hash = 1315423911; 57 | 58 | while (*str) { 59 | hash ^= ((hash << 5) + (*str++) + (hash >> 2)); 60 | } 61 | 62 | return (hash & 0x7FFFFFFF); 63 | } 64 | 65 | // P. J. Weinberger Hash Function 66 | unsigned int PJWHash(char *str) { 67 | unsigned int BitsInUnignedInt = (unsigned int)(sizeof(unsigned int) * 8); 68 | unsigned int ThreeQuarters = (unsigned int)((BitsInUnignedInt * 3) / 4); 69 | unsigned int OneEighth = (unsigned int)(BitsInUnignedInt / 8); 70 | unsigned int HighBits = (unsigned int)(0xFFFFFFFF) 71 | << (BitsInUnignedInt - OneEighth); 72 | unsigned int hash = 0; 73 | unsigned int test = 0; 74 | 75 | while (*str) { 76 | hash = (hash << OneEighth) + (*str++); 77 | if ((test = hash & HighBits) != 0) { 78 | hash = ((hash ^ (test >> ThreeQuarters)) & (~HighBits)); 79 | } 80 | } 81 | 82 | return (hash & 0x7FFFFFFF); 83 | } 84 | 85 | // ELF Hash Function 86 | unsigned int ELFHash(char *str) { 87 | unsigned int hash = 0; 88 | unsigned int x = 0; 89 | 90 | while (*str) { 91 | hash = (hash << 4) + (*str++); 92 | if ((x = hash & 0xF0000000L) != 0) { 93 | hash ^= (x >> 24); 94 | hash &= ~x; 95 | } 96 | } 97 | 98 | return (hash & 0x7FFFFFFF); 99 | } 100 | 101 | // DJB Hash Function 102 | unsigned int DJBHash(char *str) { 103 | unsigned int hash = 5381; 104 | 105 | while (*str) { 106 | hash += (hash << 5) + (*str++); 107 | } 108 | 109 | return (hash & 0x7FFFFFFF); 110 | } 111 | 112 | // AP Hash Function 113 | unsigned int APHash(char *str) { 114 | unsigned int hash = 0; 115 | int i; 116 | 117 | for (i = 0; *str; i++) { 118 | if ((i & 1) == 0) { 119 | hash ^= ((hash << 7) ^ (*str++) ^ (hash >> 3)); 120 | } else { 121 | hash ^= (~((hash << 11) ^ (*str++) ^ (hash >> 5))); 122 | } 123 | } 124 | 125 | return (hash & 0x7FFFFFFF); 126 | } 127 | -------------------------------------------------------------------------------- /String/suffix array.cpp: -------------------------------------------------------------------------------- 1 | /* suffix array 2 | 倍增算法 O(n*lgn) 3 | build_sa(num,n+1,m) 注意n+1,每个字符的值为0~m-1 4 | getHeight(num,n) 5 | rmq_init(height) 初始化rmq,传递height数组 6 | rmq(a+1,b) 求排名分别为为a和b的最长公共前缀 7 | lcp(a,b) 求后缀a和后缀b的最长公共前缀 8 | 9 | n = 8 ; 10 | num[] = { 1, 1, 2, 1, 1, 1, 1, 2, $ }. 11 | 注意num数组最后一位值为0,其它位须大于0! 12 | rank[] = { 4, 6, 8, 1, 2, 3, 5, 7, 0 }. (rank[0~n-1]为有效值) 13 | sa[] = { 8, 3, 4, 5, 0, 6, 1, 7, 2 }. (sa[1~n]为有效值) 14 | height[] = { 0, 0, 3, 2, 3, 1, 2, 0, 1 }. (height[2~n]为有效值) */ 15 | 16 | char s[N]; 17 | int d[N][20]; 18 | int num[N]; 19 | int sa[N], t1[N], t2[N], c[N], rank[N], height[N]; 20 | int n, m; 21 | 22 | void build_sa(int s[], int n, int m) { 23 | int i, k, p, *x = t1, *y = t2; 24 | //第一轮基数排序 25 | for (i = 0; i < m; i++) c[i] = 0; 26 | for (i = 0; i < n; i++) c[x[i] = s[i]]++; 27 | for (i = 1; i < m; i++) c[i] += c[i - 1]; 28 | for (i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i; 29 | for (k = 1; k <= n; k <<= 1) { 30 | p = 0; 31 | //直接利用sa数组排序第二关键字 32 | for (i = n - k; i < n; i++) y[p++] = i; 33 | for (i = 0; i < n; i++) 34 | if (sa[i] >= k) y[p++] = sa[i] - k; 35 | //基数排序第一关键字 36 | for (i = 0; i < m; i++) c[i] = 0; 37 | for (i = 0; i < n; i++) c[x[y[i]]]++; 38 | for (i = 1; i < m; i++) c[i] += c[i - 1]; 39 | for (i = n - 1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i]; 40 | //根据sa和x数组计算新的x数组 41 | swap(x, y); 42 | p = 1; 43 | x[sa[0]] = 0; 44 | for (i = 1; i < n; i++) 45 | x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k] 46 | ? p - 1 47 | : p++; 48 | if (p >= n) break; //已经排好序,直接退出 49 | m = p; //下次基数排序的最大值 50 | } 51 | } 52 | 53 | void getHeight(int s[], int n) { 54 | int i, j, k = 0; 55 | for (i = 0; i <= n; i++) rank[sa[i]] = i; 56 | for (i = 0; i < n; i++) { 57 | if (k) k--; 58 | j = sa[rank[i] - 1]; 59 | while (s[i + k] == s[j + k]) k++; 60 | height[rank[i]] = k; 61 | } 62 | } 63 | 64 | void rmq_init(int a[]) { 65 | int i, j; 66 | for (i = 1; i <= n; i++) d[i][0] = a[i]; 67 | for (j = 1; (1 << j) <= n; j++) { 68 | for (i = 1; i + (1 << j) - 1 <= n; i++) { 69 | d[i][j] = Min(d[i][j - 1], d[i + (1 << (j - 1))][j - 1]); 70 | } 71 | } 72 | } 73 | 74 | int rmq(int l, int r) { 75 | int k = 0; 76 | while ((1 << (k + 1)) <= r - l + 1) k++; 77 | return Min(d[l][k], d[r - (1 << k) + 1][k]); 78 | } 79 | 80 | int lcp(int a, int b) { 81 | if (a == b) return n - a; // a和b为同一后缀,直接输出,字串串长度为n 82 | int ra = rank[a], rb = rank[b]; 83 | if (ra > rb) swap(ra, rb); 84 | return rmq(ra + 1, rb); 85 | } 86 | -------------------------------------------------------------------------------- /String/动态Trie.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: zhaoyang.liang 3 | * @Github: https://github.com/LzyRapx 4 | * @Date: 2019-06-13 00:02:05 5 | */ 6 | /* Trie */ 7 | /* 动态建立,注意释放内存 */ 8 | const int wide = 26; //每个节点的最大子节点数 9 | 10 | struct Trie { 11 | struct Node { 12 | Node() { 13 | memset(ch, 0, sizeof(ch)); 14 | val = 0; 15 | } 16 | Node *ch[26]; 17 | int val; 18 | }; 19 | Node *head; 20 | 21 | void init() { head = new Node; } 22 | inline int idx(char c) { return c - 'a'; } 23 | void insert(char *s, int v) //插入, v 从 1 开始标号 24 | { 25 | int i, len = strlen(s), c; 26 | Node *p = head, *q; 27 | for (i = 0; i < len; i++) { 28 | c = idx(s[i]); //求对应编号 29 | if (!p->ch[c]) { 30 | q = new Node; 31 | p->ch[c] = q; 32 | } 33 | p = p->ch[c]; 34 | } 35 | p->val = v; 36 | } 37 | int find(char *s) //查找 38 | { 39 | int i, len = strlen(s), c; 40 | Node *p = head; 41 | for (i = 0; i < len; i++) { 42 | c = idx(s[i]); 43 | if (!p->ch[c]) return 0; 44 | p = p->ch[c]; 45 | } 46 | for (i = 0; i < 26; i++) { 47 | if (p->ch[i]) return 1; // s串是模板串中某个串的prefix 48 | } 49 | return 2; //存在 50 | } 51 | void free(Node *p) //释放内存 52 | { 53 | int i; 54 | for (i = 0; i < 26; i++) { 55 | if (p->ch[i]) { 56 | free(p->ch[i]); 57 | } 58 | } 59 | delete p; 60 | } 61 | } trie; 62 | -------------------------------------------------------------------------------- /String/回文树.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | const int MAXN = 300005; 3 | const int N = 26 * 2; 4 | 5 | int f(char c) { 6 | if ('a' <= c && c <= 'z') 7 | return c - 'a'; 8 | else 9 | return c - 'A' + 26; 10 | } 11 | 12 | struct Palindromic_Tree { 13 | int next 14 | [MAXN] 15 | [N]; // next指针,next指针和字典树类似,指向的串为当前串两端加上同一个字符构成 16 | int fail[MAXN]; // fail指针,失配后跳转到fail指针指向的节点 17 | int cnt[MAXN]; 18 | int num[MAXN]; 19 | int len[MAXN]; // len[i]表示节点i表示的回文串的长度 20 | int S[MAXN]; //存放添加的字符 21 | int last; //指向上一个字符所在的节点,方便下一次add 22 | int n; //字符数组指针 23 | int p; //节点指针 24 | 25 | int newnode(int l) { //新建节点 26 | for (int i = 0; i < N; ++i) next[p][i] = 0; 27 | cnt[p] = 0; 28 | num[p] = 0; 29 | len[p] = l; 30 | return p++; 31 | } 32 | 33 | void init() { //初始化 34 | p = 0; 35 | newnode(0); 36 | newnode(-1); 37 | last = 0; 38 | n = 0; 39 | S[n] = -1; //开头放一个字符集中没有的字符,减少特判 40 | fail[0] = 1; 41 | } 42 | 43 | int get_fail(int x) { //和KMP一样,失配后找一个尽量最长的 44 | while (S[n - len[x] - 1] != S[n]) x = fail[x]; 45 | return x; 46 | } 47 | 48 | void add(int c) { 49 | S[++n] = c; 50 | int cur = get_fail(last); //通过上一个回文串找这个回文串的匹配位置 51 | if (!next 52 | [cur] 53 | [c]) { //如果这个回文串没有出现过,说明出现了一个新的本质不同的回文串 54 | int now = newnode(len[cur] + 2); //新建节点 55 | fail[now] = next[get_fail( 56 | fail[cur])][c]; //和AC自动机一样建立fail指针,以便失配后跳转 57 | next[cur][c] = now; 58 | num[now] = num[fail[now]] + 1; 59 | } 60 | last = next[cur][c]; 61 | cnt[last]++; 62 | } 63 | 64 | void count() { 65 | for (int i = p - 1; i >= 0; --i) cnt[fail[i]] += cnt[i]; 66 | //父亲累加儿子的cnt,因为如果fail[v]=u,则u一定是v的子回文串! 67 | } 68 | } p; 69 | 70 | char s[N]; 71 | int i, j, k; 72 | int main() { 73 | // freopen("G.in", "r", stdin); 74 | 75 | scanf("%s", s); 76 | j = strlen(s); 77 | p.init(); 78 | for (i = 0; i < j; ++i) p.add(f(s[i])); 79 | p.count(); 80 | 81 | return 0; 82 | } -------------------------------------------------------------------------------- /String/静态Trie.cpp: -------------------------------------------------------------------------------- 1 | /* Trie */ 2 | /* 静态化,注意内存开辟大小 */ 3 | int wide = 26; //每个节点的最大子节点数 4 | int ch[1 << 18][26]; //内存开辟尽量最大 5 | int val[1 << 18]; 6 | int sz; 7 | 8 | void init() { 9 | sz = 1; 10 | memset(ch[0], 0, sizeof(ch[0])); 11 | } 12 | 13 | inline int idx(char c) //字母映射 14 | { 15 | return c - 'a'; 16 | } 17 | 18 | // v 从 1 开始标号, 19 | // 调用了insert(word[i],i)语句,如果给模板标号0的话相当于舍弃了这个模板串(v==0代表非单词结点) 20 | void insert(string s, int v) //建立Trie树, v 从 1 开始标号 21 | { 22 | int i, len = s.size(), c, u = 0; 23 | for (i = 0; i < len; i++) { 24 | c = idx(s[i]); 25 | if (!ch[u][c]) { 26 | memset(ch[sz], 0, sizeof(ch[sz])); 27 | val[sz] = 0; 28 | ch[u][c] = sz++; 29 | } 30 | u = ch[u][c]; 31 | } 32 | val[u] = v; 33 | } 34 | 35 | int find(string s) //查找 36 | { 37 | int i, len = s.size(), c, u = 0; 38 | for (i = 0; i < len; i++) { 39 | c = idx(s[i]); 40 | if (!ch[u][c]) return 0; 41 | u = ch[u][c]; 42 | } 43 | for (i = 0; i < wide; i++) { 44 | if (ch[u][c]) return 1; // s串是模板串中某个串的prefix 45 | } 46 | return 2; //存在 47 | } --------------------------------------------------------------------------------