├── .gitignore ├── demo.png ├── logo.jpg ├── CheatSheet.pdf ├── src ├── 6_计算几何 │ ├── 2_位置关系 │ │ ├── 1_两点间距离.cpp │ │ ├── 4_判断线段与直线相交.cpp │ │ ├── 7_点在线段上.cpp │ │ ├── 5_点到直线距离.cpp │ │ ├── 6_点到线段距离.cpp │ │ ├── 2_直线与直线的交点.cpp │ │ └── 3_判断线段与线段相交.cpp │ ├── 4_整数点问题 │ │ ├── 1_线段上整点个数.cpp │ │ ├── 2_多边形边上整点个数.cpp │ │ └── 3_多边形内整点个数.cpp │ ├── 3_多边形 │ │ ├── 1_多边形面积.cpp │ │ ├── 4_判断凸多边形.cpp │ │ ├── 2_点在凸多边形内.cpp │ │ ├── 3_点在任意多边形内.cpp │ │ └── 5_小结.cpp │ ├── 5_圆 │ │ └── 1_过三点求圆心.cpp │ ├── 1_定义.cpp │ └── 6_经典题 │ │ └── 1_平面最近点对.cpp ├── 2_数学 │ ├── 3_扩展欧几里得-乘法逆元 │ │ ├── 1_扩展欧几里得.cpp │ │ ├── 3_乘法逆元.cpp │ │ └── 2_求ax+by=c的解.cpp │ ├── 2_欧拉函数 │ │ ├── 1_求一个数的欧拉函数.cpp │ │ └── 2_筛法求欧拉函数.cpp │ ├── 8_其他 │ │ ├── 1_Josephus问题.cpp │ │ └── 2_数位问题.cpp │ ├── 6_快速乘+快速幂.cpp │ ├── 1_素数 │ │ ├── 1_埃氏筛.cpp │ │ ├── 4_分解质因数.cpp │ │ ├── 3_随机素数判定.cpp │ │ └── 2_欧拉筛.cpp │ ├── 7_莫比乌斯反演 │ │ ├── 3_VisibleTrees.cpp │ │ ├── 1_莫比乌斯.cpp │ │ └── 2_n个数中互质数对数.cpp │ ├── 4_模线性方程组 │ │ ├── 1_中国剩余定理.cpp │ │ └── 2_一般模线性方程组.cpp │ ├── 5_组合数学 │ │ ├── 2_Lucas定理.cpp │ │ ├── 4_Polya定理.cpp │ │ ├── 1_一般组合数.cpp │ │ └── 3_大组合数.cpp │ └── 9_相关公式.tex ├── 7_动态规划 │ └── 1_子序列 │ │ ├── 1_最大子序列和.cpp │ │ ├── 3_最长公共上升子序列LCIS.cpp │ │ └── 2_最长上升子序列LIS.cpp ├── 4_数据结构 │ ├── 1_树状数组.cpp │ ├── 2_线段树 │ │ ├── 1_声明.cpp │ │ ├── 2_单点更新-区间查询.cpp │ │ └── 3_区间更新-区间查询.cpp │ ├── 4_RMQ.cpp │ └── 3_字典树.cpp ├── 5_图论 │ ├── 3_最短路 │ │ ├── 7_Floyd算法.cpp │ │ ├── 1_Dijkstra-邻接矩阵.cpp │ │ ├── 5_Bellman-Ford(可判负环).cpp │ │ ├── 3_Dijkstra-邻接表向量.cpp │ │ ├── 2_Dijkstra-邻接表数组.cpp │ │ ├── 4_Dijkstra-优先队列.cpp │ │ └── 6_SPFA.cpp │ ├── 1_并查集.cpp │ ├── 2_最小生成树 │ │ ├── 1_Kruskal.cpp │ │ └── 2_Prim.cpp │ ├── 5_欧拉回路 │ │ ├── 1_判定.tex │ │ └── 2_求解.cpp │ └── 4_拓扑排序 │ │ ├── 1_邻接矩阵.cpp │ │ └── 2_邻接表.cpp ├── 3_字符串 │ ├── 1_KMP.cpp │ ├── 2_Manacher最长回文子串.cpp │ └── 3_AC自动机.cpp └── 1_头文件模板 │ └── 1_C++.cpp ├── Makefile ├── main.py ├── settings.py ├── README.md ├── CheatSheet.tex ├── LICENSE ├── CheatSheet.sty └── core.py /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | .idea/ 3 | -------------------------------------------------------------------------------- /demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lodour/ACM-CheatSheet/HEAD/demo.png -------------------------------------------------------------------------------- /logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lodour/ACM-CheatSheet/HEAD/logo.jpg -------------------------------------------------------------------------------- /CheatSheet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lodour/ACM-CheatSheet/HEAD/CheatSheet.pdf -------------------------------------------------------------------------------- /src/6_计算几何/2_位置关系/1_两点间距离.cpp: -------------------------------------------------------------------------------- 1 | double dist(point a, point b) { 2 | return sqrt((a - b) * (a - b)); 3 | } 4 | -------------------------------------------------------------------------------- /src/6_计算几何/4_整数点问题/1_线段上整点个数.cpp: -------------------------------------------------------------------------------- 1 | int OnSegment(line l) { 2 | return __gcd(fabs(l.s.x - l.e.x), fabs(l.s.y - l.e.y)) + 1; 3 | } 4 | -------------------------------------------------------------------------------- /src/6_计算几何/2_位置关系/4_判断线段与直线相交.cpp: -------------------------------------------------------------------------------- 1 | bool segxline(line l1, line l2) { 2 | return sgn((l2.s - l1.e) ^ (l1.s - l1.e)) * sgn((l2.e-l1.e) ^ (l1.s - l1.e)) <= 0; 3 | } 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | python3.5 main.py 3 | xelatex -shell-escape CheatSheet.tex 4 | xelatex -shell-escape CheatSheet.tex 5 | rm -f content.tex *.log *.toc *.aux *.pyg 6 | -------------------------------------------------------------------------------- /src/2_数学/3_扩展欧几里得-乘法逆元/1_扩展欧几里得.cpp: -------------------------------------------------------------------------------- 1 | void exgcd(ll a, ll b, ll &d, ll &x, ll &y) { 2 | if (!b) {d = a; x = 1; y = 0;} 3 | else {exgcd(b, a % b, d, y, x); y -= x * (a / b);} 4 | } 5 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | from core import Generator 3 | 4 | if __name__ == '__main__': 5 | with open('content.tex', 'w', encoding='utf-8') as f: 6 | f.write(Generator().populate()) 7 | -------------------------------------------------------------------------------- /src/6_计算几何/3_多边形/1_多边形面积.cpp: -------------------------------------------------------------------------------- 1 | double area(point p[], int n) { 2 | double res = 0; 3 | for (int i = 0; i < n; i++) 4 | res += (p[i] ^ p[(i + 1) % n]) / 2; 5 | return fabs(res); 6 | } 7 | -------------------------------------------------------------------------------- /src/6_计算几何/4_整数点问题/2_多边形边上整点个数.cpp: -------------------------------------------------------------------------------- 1 | int OnEdge(point p[], int n) { 2 | int i, ret = 0; 3 | for (i = 0; i < n; i++) 4 | ret += __gcd(fabs(p[i].x - p[(i + 1) % n].x), fabs(p[i].y - p[(i + 1) % n].y)); 5 | return ret; 6 | } 7 | -------------------------------------------------------------------------------- /settings.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | 3 | # 使用`\input`的后缀名 4 | INPUT_TYPE = [ 5 | 'tex', 6 | ] 7 | 8 | # 使用`\inputminted`进行高亮的后缀名 9 | CODE_TYPE = [ 10 | 'c', 11 | 'cpp', 12 | 'c++', 13 | 'java', 14 | ] 15 | -------------------------------------------------------------------------------- /src/6_计算几何/2_位置关系/7_点在线段上.cpp: -------------------------------------------------------------------------------- 1 | bool PointOnSeg(point p, line l) { 2 | return 3 | sgn((l.s - p) ^ (l.e-p)) == 0 && 4 | sgn((p.x - l.s.x) * (p.x - l.e.x)) <= 0 && 5 | sgn((p.y - l.s.y) * (p.y - l.e.y)) <= 0; 6 | } 7 | -------------------------------------------------------------------------------- /src/6_计算几何/4_整数点问题/3_多边形内整点个数.cpp: -------------------------------------------------------------------------------- 1 | int InSide(point p[], int n) { 2 | int i, area = 0; 3 | for (i = 0; i < n; i++) 4 | area += p[(i + 1) % n].y * (p[i].x - p[(i + 2) % n].x); 5 | return (fabs(area) - OnEdge(n, p)) / 2 + 1; 6 | } 7 | -------------------------------------------------------------------------------- /src/6_计算几何/2_位置关系/5_点到直线距离.cpp: -------------------------------------------------------------------------------- 1 | point pointtoline(point P, line L) { 2 | point res; 3 | double t = ((P - L.s) * (L.e-L.s)) / ((L.e-L.s) * (L.e-L.s)); 4 | res.x = L.s.x + (L.e.x - L.s.x) * t; 5 | res.y = L.s.y + (L.e.y - L.s.y) * t; 6 | return dist(P, res); 7 | } 8 | -------------------------------------------------------------------------------- /src/2_数学/2_欧拉函数/1_求一个数的欧拉函数.cpp: -------------------------------------------------------------------------------- 1 | long long Euler(long long n) { 2 | long long rt = n; 3 | for (int i = 2; i * i <= n; i++) 4 | if (n % i == 0) { 5 | rt -= rt / i; 6 | while (n % i == 0) n /= i; 7 | } 8 | if (n > 1) rt -= rt / n; 9 | return rt; 10 | } 11 | -------------------------------------------------------------------------------- /src/2_数学/2_欧拉函数/2_筛法求欧拉函数.cpp: -------------------------------------------------------------------------------- 1 | const int N = 10001; 2 | int phi[N] = {0, 1}; 3 | void CalEuler() { 4 | for (int i = 2; i < N; i++) 5 | if (!phi[i]) for (int j = i; j < N; j += i) { 6 | if (!phi[j]) phi[j] = j; 7 | phi[j] = phi[j] / i * (i - 1); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/2_数学/8_其他/1_Josephus问题.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | int main() { 4 | int num, m, r 5 | while (cin >> num >> m) { 6 | r = 0; 7 | for (int k = 1; k <= num; ++k) 8 | r = (r + m) % k; 9 | cout << r + 1 << endl; 10 | } 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /src/7_动态规划/1_子序列/1_最大子序列和.cpp: -------------------------------------------------------------------------------- 1 | // 传入序列a和长度n,返回最大子序列和 2 | // 限制最短长度:用cnt记录长度,rt更新时判断 3 | int MaxSeqSum(int a[], int n) { 4 | int rt = 0, cur = 0; 5 | for (int i = 0; i < n; i++) { 6 | cur += a[i]; 7 | rt = rt < cur ? cur : rt; 8 | cur = cur < 0 ? 0 : cur; 9 | } 10 | return rt; 11 | } 12 | -------------------------------------------------------------------------------- /src/4_数据结构/1_树状数组.cpp: -------------------------------------------------------------------------------- 1 | // $O(\log n)$查询和修改数组的前缀和 2 | // 注意下标应从1开始 n是全局变量 3 | int bit[N], n; 4 | int sum(int i){ 5 | int s = 0; 6 | while(i){ 7 | s += bit[i]; 8 | i -= i&-i; 9 | } 10 | return s; 11 | } 12 | void add(int i, int x){ 13 | while(i<=n){ 14 | bit[i] += x; 15 | i += i&-i; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/6_计算几何/3_多边形/4_判断凸多边形.cpp: -------------------------------------------------------------------------------- 1 | // 点可以是顺时针给出也可以是逆时针给出 2 | // 点的编号1~n-1 3 | bool isconvex(point poly[], int n) { 4 | bool s[3]; 5 | set(s, 0); 6 | for (int i = 0; i < n; i++) { 7 | s[sgn((poly[(i + 1) % n] - poly[i]) ^ (poly[(i + 2) % n] - poly[i]) ) + 1] = 1; 8 | if (s[0] && s[2]) return 0; 9 | } 10 | return 1; 11 | } 12 | -------------------------------------------------------------------------------- /src/6_计算几何/5_圆/1_过三点求圆心.cpp: -------------------------------------------------------------------------------- 1 | point waixin(point a, point b, point c) { 2 | double a1 = b.x - a.x, b1 = b.y - a.y, c1 = (a1 * a1 + b1 * b1) / 2; 3 | double a2 = c.x - a.x, b2 = c.y - a.y, c2 = (a2 * a2 + b2 * b2) / 2; 4 | double d = a1 * b2 - a2 * b1; 5 | return point(a.x + (c1 * b2 - c2 * b1) / d, a.y + (a1 * c2 - a2 * c1) / d); 6 | } 7 | -------------------------------------------------------------------------------- /src/2_数学/6_快速乘+快速幂.cpp: -------------------------------------------------------------------------------- 1 | ll Mul(ll a, ll b, ll mod) { 2 | ll t = 0; 3 | for (; b; b >>= 1, a = (a << 1) % mod) 4 | if (b & 1) t = (t + a) % mod; 5 | return t; 6 | } 7 | 8 | ll Pow(ll a, ll n, ll mod) { 9 | ll t = 1; 10 | for (; n; n >>= 1, a = (a * a % mod)) 11 | if (n & 1) t = (t * a % mod); 12 | return t; 13 | } 14 | -------------------------------------------------------------------------------- /src/2_数学/8_其他/2_数位问题.cpp: -------------------------------------------------------------------------------- 1 | // $n^n$最左边一位数 2 | int leftmost(int n) { 3 | double m = n * log10((double)n); 4 | double g = m - (long long)m; 5 | g = pow(10.0, g); 6 | return (int)g; 7 | } 8 | 9 | // $n!$位数 10 | int count(ll n) { 11 | return n == 1 ? 1 : (int)ceil(0.5 * log10(2 * M_PI * n) + n * log10(n) - n * log10(M_E)); 12 | } 13 | 14 | -------------------------------------------------------------------------------- /src/2_数学/1_素数/1_埃氏筛.cpp: -------------------------------------------------------------------------------- 1 | // $O(n\log\log n)$筛出MAXN内所有素数 2 | // $notprime[i] = 0/1$ 0为素数 1为非素数 3 | const int MAXN = 1000100; 4 | bool notprime[MAXN] = {1, 1}; // 0/1 为非素数 5 | void GetPrime() { 6 | for (int i = 2; i < MAXN; i++) 7 | if (!notprime[i] && i <= MAXN / i) // 筛到√n为止 8 | for (int j = i * i; j < MAXN; j += i) 9 | notprime[j] = 1; 10 | } 11 | -------------------------------------------------------------------------------- /src/6_计算几何/2_位置关系/6_点到线段距离.cpp: -------------------------------------------------------------------------------- 1 | point pointtosegment(point p, line l) { 2 | point res; 3 | double t = ((p - l.s) * (l.e-l.s)) / ((l.e-l.s) * (l.e-l.s)); 4 | if (t >= 0 && t <= 1) { 5 | res.x = l.s.x + (l.e.x - l.s.x) * t; 6 | res.y = l.s.y + (l.e.y - l.s.y) * t; 7 | } 8 | else res = dist(p, l.s) < dist(p, l.e) ? l.s : l.e; 9 | return res; 10 | } 11 | -------------------------------------------------------------------------------- /src/2_数学/3_扩展欧几里得-乘法逆元/3_乘法逆元.cpp: -------------------------------------------------------------------------------- 1 | // 利用exgcd求a在模m下的逆元,需要保证gcd(a, m) == 1. 2 | ll inv(ll a, ll m) { 3 | ll x, y, d; exgcd(a, m, d, x, y); 4 | return d == 1 ? (x + m) % m : -1; 5 | } 6 | // a < m 且 m为素数时,有以下两种求法 7 | ll inv(ll a, ll m) { 8 | return a == 1 ? 1 : inv(m % a, m) * (m - m / a) % m; 9 | } 10 | ll inv(ll a, ll m) { 11 | return Pow(a, m - 2, m); 12 | } 13 | -------------------------------------------------------------------------------- /src/2_数学/7_莫比乌斯反演/3_VisibleTrees.cpp: -------------------------------------------------------------------------------- 1 | // gcd(x,y)==1的对数 $x \leq n, y \leq m$ 2 | int main() { 3 | calmu(); 4 | int n, m; 5 | scanf("%d %d", &n, &m); 6 | if (n < m) swap(n, m); 7 | ll ans = 0; 8 | for (int i = 1; i <= m; ++i) { 9 | ans += (ll)mu[i] * (n / i) * (m / i); 10 | } 11 | printf("%lld\n", ans); 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /src/2_数学/4_模线性方程组/1_中国剩余定理.cpp: -------------------------------------------------------------------------------- 1 | // $X = r[i] % m[i]$, 要求m[i]两两互质 2 | // 引用返回通解$X = re + k * mo$ 3 | void crt(ll r[], ll m[], ll n, ll &re, ll &mo) { 4 | mo = 1, re = 0; 5 | for (int i = 0; i < n; i++) mo *= m[i]; 6 | for (int i = 0; i < n; i++) { 7 | ll x, y, d, tm = mo / m[i]; 8 | exgcd(tm, m[i], d, x, y); 9 | re = (re + tm * x * r[i]) % mo; 10 | } re = (re + mo) % mo; 11 | } 12 | -------------------------------------------------------------------------------- /src/7_动态规划/1_子序列/3_最长公共上升子序列LCIS.cpp: -------------------------------------------------------------------------------- 1 | // 序列下标从1开始 2 | int LCIS(int a[], int b[], int n, int m) { 3 | set(dp, 0); 4 | for (int i = 1; i <= n; i++) { 5 | int ma = 0; 6 | for (int j = 1; j <= m; j++) { 7 | dp[i][j] = dp[i - 1][j]; 8 | if (a[i] > b[j]) ma = max(ma, dp[i - 1][j]); 9 | if (a[i] == b[j]) dp[i][j] = ma + 1; 10 | } 11 | } 12 | return *max_element(dp[n] + 1, dp[n] + 1 + m); 13 | } 14 | -------------------------------------------------------------------------------- /src/6_计算几何/3_多边形/2_点在凸多边形内.cpp: -------------------------------------------------------------------------------- 1 | // 点形成一个凸包, 而且按逆时针排序(如果是顺时针把里面的<0改为>0) 2 | // 点的编号 : [0,n) 3 | // -1 : 点在凸多边形外 4 | // 0 : 点在凸多边形边界上 5 | // 1 : 点在凸多边形内 6 | int PointInConvex(point a, point p[], int n) { 7 | for (int i = 0; i < n; i++) { 8 | if (sgn((p[i] - a) ^ (p[(i + 1) % n] - a)) < 0) 9 | return -1; 10 | else if (PointOnSeg(a, line(p[i], p[(i + 1) % n]))) 11 | return 0; 12 | } 13 | return 1; 14 | } 15 | -------------------------------------------------------------------------------- /src/4_数据结构/2_线段树/1_声明.cpp: -------------------------------------------------------------------------------- 1 | #define lson rt<<1 // 左儿子 2 | #define rson rt<<1|1 // 右儿子 3 | #define Lson l,m,lson // 左子树 4 | #define Rson m+1,r,rson // 右子树 5 | void PushUp(int rt); // 用lson和rson更新rt 6 | void PushDown(int rt[, int m]); // rt的标记下移,m为区间长度(若与标记有关) 7 | void build(int l, int r, int rt); // 以rt为根节点,对区间[l, r]建立线段树 8 | void update([...,] int l, int r, int rt) // rt[l, r]内寻找目标并更新 9 | int query(int L, int R, int l, int r, int rt) // rt-[l, r]内查询[L, R] 10 | -------------------------------------------------------------------------------- /src/6_计算几何/2_位置关系/2_直线与直线的交点.cpp: -------------------------------------------------------------------------------- 1 | // <0, *> 表示重合; <1, *> 表示平行; <2, P> 表示交点是P; 2 | pair spoint(line l1, line l2) { 3 | point res = l1.s; 4 | if (sgn((l1.s - l1.e) ^ (l2.s - l2.e)) == 0) 5 | return mp(sgn((l1.s - l2.e) ^ (l2.s - l2.e)) != 0, res); 6 | double t = ((l1.s - l2.s) ^ (l2.s - l2.e)) / ((l1.s - l1.e) ^ (l2.s - l2.e)); 7 | res.x += (l1.e.x - l1.s.x) * t; 8 | res.y += (l1.e.y - l1.s.y) * t; 9 | return mp(2, res); 10 | } -------------------------------------------------------------------------------- /src/2_数学/4_模线性方程组/2_一般模线性方程组.cpp: -------------------------------------------------------------------------------- 1 | // $X = r[i] % m[i]$, m[i]可以不两两互质 2 | // 引用返回通解$X = re + k * mo$, 函数返回是否有解 3 | bool excrt(ll r[], ll m[], ll n, ll &re, ll &mo) { 4 | ll x, y, d; mo = m[0], re = r[0]; 5 | for (int i = 1; i < n; i++) { 6 | exgcd(mo, m[i], d, x, y); 7 | if ((r[i] - re) % d != 0) return 0; 8 | x = (r[i] - re) / d * x % (m[i] / d); 9 | re += x * mo; 10 | mo = mo / d * m[i]; 11 | re %= mo; 12 | } re = (re + mo) % mo; 13 | return 1; 14 | } 15 | -------------------------------------------------------------------------------- /src/2_数学/3_扩展欧几里得-乘法逆元/2_求ax+by=c的解.cpp: -------------------------------------------------------------------------------- 1 | // 引用返回通解: $X = x + k * dx, Y = y – k * dy$ 2 | // 引用返回的x是最小非负整数解,方程无解函数返回0 3 | #define Mod(a,b) (((a)%(b)+(b))%(b)) 4 | bool solve(ll a, ll b, ll c, ll &x, ll &y, ll &dx, ll &dy) { 5 | if (a == 0 && b == 0) return 0; 6 | ll d, x0, y0; exgcd(a, b, d, x0, y0); 7 | if (c % d != 0) return 0; 8 | dx = b / d; dy = a / d; 9 | x = Mod(x0 * c / d, dx); y = (c - a * x) / b; 10 | // y = Mod(y0 * c / d, dy); x = (c - b * y) / a; 11 | return 1; 12 | } 13 | -------------------------------------------------------------------------------- /src/2_数学/5_组合数学/2_Lucas定理.cpp: -------------------------------------------------------------------------------- 1 | // $1 \leq n, m \leq 10^9, 1 < p < 10^5$, p是素数 2 | const int maxp = 100010; 3 | ll f[maxp]; 4 | void CalFact(ll p) { 5 | f[0] = 1; 6 | for (int i = 1; i <= p; i++) 7 | f[i] = (f[i - 1] * i) % p; 8 | } 9 | ll Lucas(ll n, ll m, ll p) { 10 | ll ret = 1; 11 | while (n && m) { 12 | ll a = n % p, b = m % p; 13 | if (a < b) return 0; 14 | ret = (ret * f[a] * Pow(f[b] * f[a - b] % p, p - 2, p)) % p; 15 | n /= p; m /= p; 16 | } 17 | return ret; 18 | } 19 | -------------------------------------------------------------------------------- /src/6_计算几何/2_位置关系/3_判断线段与线段相交.cpp: -------------------------------------------------------------------------------- 1 | bool segxseg(line l1, line l2) { 2 | return 3 | max(l1.s.x, l1.e.x) >= min(l2.s.x, l2.e.x) && 4 | max(l2.s.x, l2.e.x) >= min(l1.s.x, l1.e.x) && 5 | max(l1.s.y, l1.e.y) >= min(l2.s.y, l2.e.y) && 6 | max(l2.s.y, l2.e.y) >= min(l1.s.y, l1.e.y) && 7 | sgn((l2.s - l1.e) ^ (l1.s - l1.e)) * sgn((l2.e-l1.e) ^ (l1.s - l1.e)) <= 0 && 8 | sgn((l1.s - l2.e) ^ (l2.s - l2.e)) * sgn((l1.e-l2.e) ^ (l2.s - l2.e)) <= 0; 9 | } 10 | -------------------------------------------------------------------------------- /src/5_图论/3_最短路/7_Floyd算法.cpp: -------------------------------------------------------------------------------- 1 | // $O(n^3)$求出任意两点间最短路 2 | const int MAXN = "Edit"; 3 | const int INF = 0x3F3F3F3F; 4 | int G[MAXN][MAXN]; 5 | void init(int n) { 6 | memset(G, 0x3F, sizeof(G)); 7 | for (int i = 0; i < n; i++) 8 | G[i][i] = 0; 9 | } 10 | void add_edge(int u, int v, int w) { 11 | G[u][v] = min(G[u][v], w); 12 | } 13 | void Floyd(int n) { 14 | for (int k = 0; k < n; k++) 15 | for (int i = 0; i < n; i++) 16 | for (int j = 0; j < n; j++) 17 | G[i][j] = min(G[i][j], G[i][k] + G[k][j]); 18 | } 19 | -------------------------------------------------------------------------------- /src/2_数学/1_素数/4_分解质因数.cpp: -------------------------------------------------------------------------------- 1 | // 函数返回素因数个数 2 | // 数组以$fact[i][0]^{fact[i][1]}$的形式保存第i个素因数 3 | ll fact[100][2]; 4 | int getFactors(ll x) { 5 | int cnt = 0; 6 | for (int i = 0; prime[i] <= x / prime[i]; i++) { 7 | fact[cnt][1] = 0; 8 | if (x % prime[i] == 0 ) { 9 | fact[cnt][0] = prime[i]; 10 | while (x % prime[i] == 0) { 11 | fact[cnt][1]++; 12 | x /= prime[i]; 13 | } 14 | cnt++; 15 | } 16 | } 17 | if (x != 1) { 18 | fact[cnt][0] = x; 19 | fact[cnt++][1] = 1; 20 | } 21 | return cnt; 22 | } 23 | -------------------------------------------------------------------------------- /src/2_数学/1_素数/3_随机素数判定.cpp: -------------------------------------------------------------------------------- 1 | // $O(s\log n)$内判定$2^{63}$内的数是不是素数,$s$为测定次数 2 | bool Miller_Rabin(ll n, int s) { 3 | if (n == 2) return 1; 4 | if (n < 2 || !(n & 1)) return 0; 5 | int t = 0; ll x, y, u = n - 1; 6 | while ((u & 1) == 0) t++, u >>= 1; 7 | for (int i = 0; i < s; i++) { 8 | ll a = rand() % (n - 1) + 1; 9 | ll x = Pow(a, u, n); 10 | for (int j = 0; j < t; j++) { 11 | ll y = Mul(x, x, n); 12 | if (y == 1 && x != 1 && x != n - 1) return 0; 13 | x = y; 14 | } 15 | if (x != 1) return 0; 16 | } 17 | return 1; 18 | } 19 | -------------------------------------------------------------------------------- /src/2_数学/5_组合数学/4_Polya定理.cpp: -------------------------------------------------------------------------------- 1 | // 推论:一共$n$个置换,第$i$个置换的循环节个数为$gcd(i,n)$ 2 | // $N*N$的正方形格子,$c^{n^2}+2c^{\frac{n^2+3}{4}}+c^{\frac{n^2+1}{2}}+2c^{n\frac{n+1}{2}}+2c^{\frac{n(n+1)}{2}}$ 3 | // 正六面体,$(m^8+17m^4+6m^2)/24$ 4 | // 正四面体,$(m^4+11m^2)/12$ 5 | // 长度为n的项链串用c种颜色染 6 | ll solve(int c, int n) { 7 | if (n == 0) return 0; 8 | ll ans = 0; 9 | for (int i = 1; i <= n; i++) 10 | ans += Pow(c, __gcd(i, n)); 11 | if (n & 1) 12 | ans += n * Pow(c, n + 1 >> 1); 13 | else 14 | ans += n / 2 * (1 + c) * Pow(c, n >> 1); 15 | return ans / n / 2; 16 | } 17 | -------------------------------------------------------------------------------- /src/5_图论/1_并查集.cpp: -------------------------------------------------------------------------------- 1 | const int MAXN = 128; 2 | int n, fa[MAXN], ra[MAXN]; 3 | void init() { 4 | for (int i = 0; i <= n; i++) { 5 | fa[i] = i; ra[i] = 0; 6 | } 7 | } 8 | int find(int x) { 9 | if (fa[x] != x) fa[x] = find(fa[x]); 10 | return fa[x]; 11 | } 12 | void unite(int x, int y) { 13 | x = find(x); y = find(y); if (x == y) return; 14 | if (ra[x] < ra[y]) fa[x] = y; 15 | else { 16 | fa[y] = x; if (ra[x] == ra[y]) ra[x]++; 17 | } 18 | } 19 | bool same(int x, int y) { 20 | return find(x) == find(y); 21 | } 22 | -------------------------------------------------------------------------------- /src/3_字符串/1_KMP.cpp: -------------------------------------------------------------------------------- 1 | // 返回y中x的个数 2 | int ne[N]; 3 | void initkmp(char x[], int m) { 4 | int i, j; j = ne[0] = -1; i = 0; 5 | while (i < m) { 6 | while (j != -1 && x[i] != x[j]) 7 | j = ne[j]; 8 | ne[++i] = ++j; 9 | } 10 | } 11 | int kmp(char x[], int m, char y[], int n) { 12 | int i, j, ans; i = j = ans = 0; 13 | initkmp (x, m); 14 | while (i < n) { 15 | while (j != -1 && y[i] != x[j]) j = ne[j]; 16 | i++; j++; 17 | if (j >= m) { 18 | ans++; j = ne[j]; 19 | } 20 | } 21 | return ans; 22 | } -------------------------------------------------------------------------------- /src/2_数学/5_组合数学/1_一般组合数.cpp: -------------------------------------------------------------------------------- 1 | // $0 \leq m \leq n \leq 1000$ 2 | const int maxn = 1010; 3 | ll C[maxn][maxn]; 4 | void CalComb() { 5 | C[0][0] = 1; 6 | for (int i = 1; i < maxn; i++) { 7 | C[i][0] = 1; 8 | for (int j = 1; j <= i; j++) 9 | C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod; 10 | } 11 | } 12 | 13 | // $0 \leq m \leq n \leq 10^5$, 模p为素数 14 | const int maxn = 100010; 15 | ll f[maxn]; 16 | void CalFact() { 17 | f[0] = 1; 18 | for (int i = 1; i < maxn; i++) 19 | f[i] = (f[i - 1] * i) % mod; 20 | } 21 | ll C(int n, int m) { 22 | return f[n] * inv(f[m] * f[n - m] % mod, mod) % mod; 23 | } 24 | -------------------------------------------------------------------------------- /src/5_图论/2_最小生成树/1_Kruskal.cpp: -------------------------------------------------------------------------------- 1 | vector > G; 2 | void add_edge(int u, int v, int d) { 3 | G.pb(mp(d, mp(u, v))); 4 | } 5 | int Kruskal(int n) { 6 | init(n); 7 | sort(G.begin(), G.end()); 8 | int m = G.size(); 9 | int num = 0, ret = 0; 10 | for (int i = 0; i < m; i++) { 11 | pair p = G[i]; 12 | int x = p.Y.X; 13 | int y = p.Y.Y; 14 | int d = p.X; 15 | if (!same(x, y)) { 16 | unite(x, y); 17 | num++; 18 | ret += d; 19 | } 20 | if (num == n - 1) break; 21 | } 22 | return ret; 23 | } 24 | -------------------------------------------------------------------------------- /src/2_数学/1_素数/2_欧拉筛.cpp: -------------------------------------------------------------------------------- 1 | // $O(n)$得到欧拉函数$phi[]$、素数表$prime[]$、素数个数$tot$ 2 | // 传入的n为函数定义域上界 3 | const int MAXN = 100010; 4 | bool vis[MAXN]; 5 | int tot, phi[MAXN], prime[MAXN]; 6 | void CalPhi(int n) { 7 | set(vis, 0); phi[1] = 1; tot = 0; 8 | for (int i = 2; i < n; i++) { 9 | if (!vis[i]) { 10 | prime[tot++] = i; 11 | phi[i] = i - 1; 12 | } 13 | for (int j = 0; j < tot; j++) { 14 | if (i * prime[j] > n) break; 15 | vis[i * prime[j]] = 1; 16 | if (i % prime[j] == 0) { 17 | phi[i * prime[j]] = phi[i] * prime[j]; 18 | break; 19 | } 20 | else phi[i * prime[j]] = phi[i] * (prime[j] - 1); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/5_图论/5_欧拉回路/1_判定.tex: -------------------------------------------------------------------------------- 1 | \begin{theorem} 2 | 无向图G存在欧拉通路的充要条件是:G为连通图,并且G仅有两个奇度结点或无奇度结点。 3 | \end{theorem} 4 | 5 | \begin{corollary} 6 | (1) 当G是仅有两个奇度结点的连通图时,G的欧拉通路必以此两个结点为端点。 7 | (2) 当G时无奇度结点的连通图时,G必有欧拉回路。 8 | (3) G为欧拉图(存在欧拉回路)的充要条件是G为无奇度结点的连通图。 9 | \end{corollary} 10 | 11 | \begin{theorem} 12 | 有向图D存在欧拉通路的充要条件是:D为有向图,D的基图连通,并且所有顶点的出度与入度都相等;或者除两个顶点外,其余顶点的出度与入度都相等,而这两个顶点中一个顶点的出度与入度只差为1,另一个顶点的出度与入度之差为-1。 13 | \end{theorem} 14 | 15 | \begin{corollary} 16 | (1) 当D除出、入度之差为1,-1的两个顶点之外,其余顶点的出度与入度都相等时,D的有向欧拉通路必以出、入度之差为1的顶点作为始点,以出、入度之差为-1的顶点作为终点。 17 | (2) 当D的所有顶点的出、入度都相等时,D中存在有向欧拉回路。 18 | (3) 有向图D为有向欧拉图的充要条件是D的基图为连通图,并且所有顶点的出、入度都相等。 19 | \end{corollary} 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ACM-ICPC CheatSheet 2 | ![python](https://img.shields.io/badge/python-3.5-ff69b4.svg) 3 | 4 | ACM-ICPC模板 5 | 6 | ## Feature 7 | * 维护模板代码,自动生成PDF,[CheatSheet.pdf](CheatSheet.pdf) 8 | * 代码高亮,代码中渲染数学公式 9 | * 可直接插入`tex`文件 10 | * 仅包含一个文件的目录,会将该文件直接作为一个章节 11 | * 已有模板仅作为参考 12 | 13 | ## Usage 14 | 1. 模板代码 15 | 16 | * 依照`/src`目录下的格式进行排布。 17 | 18 | 2. 设置 19 | 20 | * 自行配置`xelatex`编译环境 21 | * `CheatSheet.sty`: 修改latex的相关样式 22 | * `CheatSheet.tex`: 修改`Title`或`Owner Information`部分的信息 23 | * `settings.py`: 请在此文件中添加其他代码语言 24 | 25 | 3. 运行 26 | 27 | `make build` 28 | 29 | ## License 30 | [MIT License](LICENSE) 31 | 32 | ## Demo 33 | ![](demo.png) 34 | -------------------------------------------------------------------------------- /CheatSheet.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt,a4paper]{article} 2 | \usepackage{CheatSheet} 3 | 4 | \begin{document} 5 | 6 | % 标题页 7 | \begin{titlepage} 8 | \begin{center} 9 | % Logo 10 | \vspace*{0.5cm} 11 | \includegraphics[width=0.75\textwidth]{logo.jpg} \\ [2cm] 12 | 13 | % Title 14 | \HRule \\ [1cm] 15 | \textbf{\Huge{ACM-ICPC Cheat Sheet}} \\ [0.5cm] 16 | \HRule \\ [4cm] 17 | 18 | % Owner Information 19 | \textbf{\Huge{School Name}} \\ [1cm] 20 | \LARGE{Team Name} 21 | 22 | % Footer 23 | \vfill 24 | \Large{\today} 25 | \end{center} 26 | \clearpage 27 | 28 | % Contents 29 | \tableofcontents 30 | \pagestyle{empty} 31 | \clearpage 32 | \end{titlepage} 33 | 34 | % 正文 35 | \input{content.tex} 36 | 37 | \end{document} 38 | -------------------------------------------------------------------------------- /src/7_动态规划/1_子序列/2_最长上升子序列LIS.cpp: -------------------------------------------------------------------------------- 1 | // 序列下标从1开始,LIS()返回长度,序列存在lis[]中 2 | #define N 100100 3 | int n, len, a[N], b[N], f[N]; 4 | int Find(int p, int l, int r) { 5 | int mid; 6 | while (l <= r) { 7 | mid = (l + r) >> 1; 8 | if (a[p] > b[mid]) l = mid + 1; 9 | else r = mid - 1; 10 | } 11 | return f[p] = l; 12 | } 13 | int LIS(int lis[]) { 14 | int len = 1; 15 | f[1] = 1; 16 | b[1] = a[1]; 17 | for (int i = 2; i <= n; i++) { 18 | if (a[i] > b[len]) b[++len] = a[i], f[i] = len; 19 | else b[Find(i, 1, len)] = a[i]; 20 | } 21 | for (int i = n, t = len; i >= 1 && t >= 1; i--) 22 | if (f[i] == t) 23 | lis[--t] = a[i]; 24 | return len; 25 | } 26 | -------------------------------------------------------------------------------- /src/5_图论/2_最小生成树/2_Prim.cpp: -------------------------------------------------------------------------------- 1 | // 耗费矩阵cost[][],标号从0开始,0~n-1 2 | // 返回最小生成树的权值,返回-1表示原图不连通 3 | const int INF = 0x3f3f3f3f; 4 | const int MAXN = 110; 5 | bool vis[MAXN]; 6 | int lowc[MAXN]; 7 | int Prim(int cost[][MAXN], int n) { 8 | int ans = 0; 9 | set(vis, 0); 10 | vis[0] = 1; 11 | for (int i = 1; i < n; i++) 12 | lowc[i] = cost[0][i]; 13 | for (int i = 1; i < n; i++) { 14 | int minc = INF; 15 | int p = -1; 16 | for (int j = 0; j < n; j++) 17 | if (!vis[j] && minc > lowc[j]) { 18 | minc = lowc[j]; 19 | p = j; 20 | } 21 | if (minc == INF) return -1; 22 | vis[p] = 1; 23 | for (int j = 0; j < n; j++) 24 | if (!vis[j] && lowc[j] > cost[p][j]) lowc[j] = cost[p][j]; 25 | } 26 | return ans; 27 | } 28 | -------------------------------------------------------------------------------- /src/5_图论/3_最短路/1_Dijkstra-邻接矩阵.cpp: -------------------------------------------------------------------------------- 1 | // N为点数最大值 求s到所有点的最短路 2 | // 要求边权值为非负数 模板为有向边 3 | // dis[x]为起点到点x的最短路 inf表示无法走到 4 | // 记得初始化 5 | const int N = 100; // 点数最大值 6 | const int INF = 0x3f3f3f3f; 7 | int G[N][N], dis[N]; 8 | bool vis[N]; 9 | void init(int n) { 10 | set(G, 0x3f); 11 | } 12 | void add_edge(int u, int v, int w) { 13 | G[u][v] = min(G[u][v], w); 14 | } 15 | void Dijkstra(int s, int n) { 16 | set(vis, 0); 17 | set(dis, 0x3f); 18 | dis[s] = 0; 19 | for (int i = 0; i < n; i++) { 20 | int x, minDis = INF; 21 | for (int j = 0; j < n; j++) { 22 | if (!vis[j] && dis[j] <= minDis) { 23 | x = j; 24 | minDis = dis[j]; 25 | } 26 | } 27 | vis[x] = 1; 28 | for (int j = 0; j < n; j++) 29 | dis[j] = min(dis[j], dis[x] + G[x][j]); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/4_数据结构/4_RMQ.cpp: -------------------------------------------------------------------------------- 1 | const int MAXN = 200000 + 100; 2 | int mmax[MAXN][30], mmin[MAXN][30]; 3 | int a[MAXN], n, k; 4 | 5 | void init() { 6 | for (int i = 1; i <= n; i++) { 7 | mmax[i][0] = mmin[i][0] = a[i]; 8 | } 9 | for (int j = 1; (1 << j) <= n; j++) 10 | for (int i = 1; i + (1 << j) - 1 <= n; i++) { 11 | mmax[i][j] = max(mmax[i][j - 1], mmax[i + (1 << (j - 1))][j - 1]); 12 | mmin[i][j] = min(mmin[i][j - 1], mmin[i + (1 << (j - 1))][j - 1]); 13 | } 14 | } 15 | 16 | // op=0/1 返回[l,r]最大/小值 17 | int rmq(int l, int r, int op) { 18 | int k = 0; 19 | while ((1 << (k + 1)) <= r - l + 1) k++; 20 | if (op == 0) return max(mmax[l][k], mmax[r - (1 << k) + 1][k]); 21 | return min(mmin[l][k], mmin[r - (1 << k) + 1][k]); 22 | } 23 | -------------------------------------------------------------------------------- /src/4_数据结构/2_线段树/2_单点更新-区间查询.cpp: -------------------------------------------------------------------------------- 1 | const int maxn = 50010; 2 | int sum[maxn << 2]; 3 | void PushUp(int rt) { 4 | sum[rt] = sum[lson] + sum[rson]; 5 | } 6 | void build(int l, int r, int rt) { 7 | if (l == r) {scanf("%d", &sum[rt]); return;} // 建立的时候直接输入叶节点 8 | int m = (l + r) >> 1; 9 | build(Lson); build(Rson); 10 | PushUp(rt); 11 | } 12 | void update(int p, int add, int l, int r, int rt) { 13 | if (l == r) {sum[rt] += add; return;} 14 | int m = (l + r) >> 1; 15 | if (p <= m) update(p, add, Lson); 16 | else update(p, add, Rson); 17 | PushUp(rt); 18 | } 19 | int query(int L, int R, int l, int r, int rt) { 20 | if (L <= l && r <= R) {return sum[rt];} 21 | int m = (l + r) >> 1, s = 0; 22 | if (L <= m) s += query(L, R, Lson); 23 | if (m < R) s += query(L, R, Rson); 24 | return s; 25 | } 26 | -------------------------------------------------------------------------------- /src/6_计算几何/3_多边形/3_点在任意多边形内.cpp: -------------------------------------------------------------------------------- 1 | // 射线法,poly[]的顶点数要大于等于3,点的编号0~n-1 2 | // -1 : 点在凸多边形外 3 | // 0 : 点在凸多边形边界上 4 | // 1 : 点在凸多边形内 5 | int PointInPoly(point p, point poly[], int n) { 6 | int cnt; 7 | line ray, side; 8 | cnt = 0; 9 | ray.s = p; 10 | ray.e.y = p.y; 11 | ray.e.x = -100000000000.0; // -INF,注意取值防止越界 12 | for (int i = 0; i < n; i++) { 13 | side.s = poly[i]; 14 | side.e = poly[(i + 1) % n]; 15 | if (PointOnSeg(p, side))return 0; 16 | //如果平行轴则不考虑 17 | if (sgn(side.s.y - side.e.y) == 0) 18 | continue; 19 | if (PointOnSeg(sid e.s, r ay)) { 20 | if (sgn(side.s.y - side.e.y) > 0) cnt++; 21 | } 22 | else if (PointOnSeg(side.e, ray)) { 23 | if (sgn(side.e.y - side.s.y) > 0) cnt++; 24 | } 25 | else if (segxseg(ray, side)) cnt++; 26 | } 27 | return cnt % 2 == 1 ? 1 : -1; 28 | } 29 | -------------------------------------------------------------------------------- /src/5_图论/4_拓扑排序/1_邻接矩阵.cpp: -------------------------------------------------------------------------------- 1 | // 存图前记得初始化 2 | // Ans存放拓排结果,G为邻接矩阵,deg为入度信息 3 | // 排序成功返回1,存在环返回0 4 | const int MAXN = "Edit"; 5 | int Ans[MAXN]; // 存放拓扑排序结果 6 | int G[MAXN][MAXN]; // 存放图信息 7 | int deg[MAXN]; // 存放点入度信息 8 | void init() { 9 | memset(G, 0, sizeof(G)); 10 | memset(deg, 0, sizeof(deg)); 11 | memset(Ans, 0, sizeof(Ans)); 12 | } 13 | void add_edge(int u, int v) { 14 | if (G[u][v]) return; 15 | G[u][v] = 1; 16 | deg[v]++; 17 | } 18 | bool Toposort(int n) { 19 | int tot = 0; 20 | queue que; 21 | for (int i = 0; i < n; ++i) 22 | if (deg[i] == 0) que.push(i); 23 | while (!que.empty()) { 24 | int v = que.front(); que.pop(); 25 | Ans[tot++] = v; 26 | for (int i = 0; i < n; ++i) 27 | if (G[v][i] == 1) 28 | if (--deg[t] == 0) que.push(t); 29 | } 30 | if (tot < n) return false; 31 | return true; 32 | } 33 | -------------------------------------------------------------------------------- /src/2_数学/7_莫比乌斯反演/1_莫比乌斯.cpp: -------------------------------------------------------------------------------- 1 | // $F(n)=\sum_{d|n}f(d)\Rightarrow f(n)=\sum_{d|n}\mu(d)F(\frac{n}{d})$ 2 | // $F(n)=\sum_{n|d}f(d)\Rightarrow f(n)=\sum_{n|d}\mu(\frac{d}{n})F(d)$ 3 | long long ans; 4 | const int MAXN = 1e5 + 1; 5 | int n, x, prime[MAXN], tot, mu[MAXN]; 6 | bool check[MAXN]; 7 | void calmu() { 8 | mu[1] = 1; 9 | for (int i = 2; i < MAXN; i++) { 10 | if (!check[i]) { 11 | prime[tot++] = i; 12 | mu[i] = -1; 13 | } 14 | for (int j = 0; j < tot; j++) { 15 | if (i * prime[j] >= MAXN) break; 16 | check[i * prime[j]] = true; 17 | if (i % prime[j] == 0) { 18 | mu[i * prime[j]] = 0; 19 | break; 20 | } else { 21 | mu[i * prime[j]] = -mu[i]; 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/3_字符串/2_Manacher最长回文子串.cpp: -------------------------------------------------------------------------------- 1 | // O(n)求解最长回文子串 2 | const int N = 1000100; 3 | char s[N], str[N << 1]; 4 | int p[N << 1]; 5 | void Manacher(char s[], int &n) { 6 | str[0] = '$'; 7 | str[1] = '#'; 8 | for (int i = 0; i < n; i++) { 9 | str[(i << 1) + 2] = s[i]; 10 | str[(i << 1) + 3] = '#'; 11 | } 12 | n = 2 * n + 2; 13 | str[n] = 0; 14 | int mx = 0, id; 15 | for (int i = 1; i < n; i++) { 16 | p[i] = mx > i ? min(p[2 * id - i], mx - i) : 1; 17 | while(str[i - p[i]] == str[i + p[i]]) p[i]++; 18 | if (p[i] + i > mx) { 19 | mx = p[i] + i; 20 | id = i; 21 | } 22 | } 23 | } 24 | int solve(char s[]) { 25 | int n = strlen(s); 26 | Manacher(s, n); 27 | int res = 0; 28 | for (int i = 0; i < n; i++) 29 | res = max(res, p[i]); 30 | return res - 1; 31 | } 32 | -------------------------------------------------------------------------------- /src/5_图论/3_最短路/5_Bellman-Ford(可判负环).cpp: -------------------------------------------------------------------------------- 1 | // 求出起点s到每个点x的最短路dis[x] 2 | // 存在负环返回1 否则返回0 3 | // 记得初始化 4 | const int MAX_N = "Edit"; // 点数最大值 5 | const int MAX_E = "Edit"; // 边数最大值 6 | const int INF = 0x3F3F3F3F; 7 | int From[MAX_E], To[MAX_E], W[MAX_E]; 8 | int dis[MAX_N], tot; 9 | void init() {tot = 0;} 10 | void add_edge(int u, int v, int d) { 11 | From[tot] = u; 12 | To[tot] = v; 13 | W[tot++] = d; 14 | } 15 | bool Bellman_Ford(int s, int n) { 16 | memset(dis, 0x3F, sizeof(dis)); 17 | dis[s] = 0; 18 | for (int k = 0; k < n - 1; k++) { 19 | bool relaxed = 0; 20 | for (int i = 0; i < tot; i++) { 21 | int x = From[i], y = To[i]; 22 | if (dis[y] > dis[x] + W[i]) { 23 | dis[y] = dis[x] + W[i]; 24 | relaxed = 1; 25 | } 26 | } 27 | if (!relaxed) break; 28 | } 29 | for (int i = 0; i < tot; i++) 30 | if (dis[To[i]] > dis[From[i]] + W[i]) 31 | return 1; 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /src/2_数学/5_组合数学/3_大组合数.cpp: -------------------------------------------------------------------------------- 1 | // $0 \leq n \leq 10^9, 0 \leq m \leq 10^4, 1 \leq k \leq 10^9+7$ 2 | vector v; 3 | int dp[110]; 4 | ll Cal(int l, int r, int k, int dis) { 5 | ll res = 1; 6 | for (int i = l; i <= r; i++) { 7 | int t = i; 8 | for (int j = 0; j < v.size(); j++) { 9 | int y = v[j]; 10 | while (t % y == 0) { 11 | dp[j] += dis; 12 | t /= y; 13 | } 14 | } 15 | res = res * (ll)t % k; 16 | } 17 | return res; 18 | } 19 | ll Comb(int n, int m, int k) { 20 | set(dp, 0); v.clear(); int tmp = k; 21 | for (int i = 2; i * i <= tmp; i++) { 22 | if (tmp % i == 0) { 23 | int num = 0; 24 | while (tmp % i == 0) { 25 | tmp /= i; 26 | num++; 27 | } 28 | v.pb(i); 29 | } 30 | } if (tmp != 1) v.pb(tmp); 31 | ll ans = Cal(n - m + 1, n, k, 1); 32 | for (int j = 0; j < v.size(); j++) { 33 | ans = ans * Pow(v[j], dp[j], k) % k; 34 | } 35 | ans = ans * inv(Cal(2, m, k, -1), k) % k; 36 | return ans; 37 | } 38 | -------------------------------------------------------------------------------- /src/5_图论/4_拓扑排序/2_邻接表.cpp: -------------------------------------------------------------------------------- 1 | // 存图前记得初始化 2 | // Ans排序结果,G邻接表,deg入度,map用于判断重边 3 | // 排序成功返回1,存在环返回0 4 | const int MAXN = "Edit"; 5 | typedef pair PII; 6 | int Ans[MAXN]; 7 | vector G[MAXN]; 8 | int deg[MAXN]; 9 | map S; 10 | void init(int n) { 11 | S.clear(); 12 | for (int i = 0; i < n; i++)G[i].clear(); 13 | memset(deg, 0, sizeof(deg)); 14 | memset(Ans, 0, sizeof(Ans)); 15 | } 16 | void add_edge(int u, int v) { 17 | if (S[make_pair(u, v)]) return; 18 | G[u].push_back(v); 19 | S[make_pair(u, v)] = 1; 20 | deg[v]++; 21 | } 22 | bool Toposort(int n) { 23 | int tot = 0; queue que; 24 | for (int i = 0; i < n; ++i) 25 | if (deg[i] == 0) que.push(i); 26 | while (!que.empty()) { 27 | int v = que.front(); que.pop(); 28 | Ans[tot++] = v; 29 | for (int i = 0; i < G[v].size(); ++i) { 30 | int t = G[v][i]; 31 | if (--deg[t] == 0) que.push(t); 32 | } 33 | } 34 | if (tot < n) return false; 35 | return true; 36 | } 37 | -------------------------------------------------------------------------------- /src/5_图论/3_最短路/3_Dijkstra-邻接表向量.cpp: -------------------------------------------------------------------------------- 1 | // MAXN: 点数最大值 2 | // 求起点s到所有点x的最短路dis[x] 3 | // 记得初始化 4 | const int MAXN = "Edit"; 5 | const int INF = 0x3F3F3F3F; 6 | vector G[MAXN]; 7 | vector GW[MAXN]; 8 | bool vis[MAXN]; 9 | int dis[MAXN]; 10 | void init(int n) { 11 | for (int i = 0; i < n; i++) { 12 | G[i].clear(); 13 | GW[i].clear(); 14 | } 15 | } 16 | void add_edge(int u, int v, int w) { 17 | G[u].push_back(v); 18 | GW[u].push_back(w); 19 | } 20 | void Dijkstra(int s, int n) { 21 | memset(vis, false, sizeof(vis)); 22 | memset(dis, 0x3F, sizeof(dis)); 23 | dis[s] = 0; 24 | for (int i = 0; i < n; i++) { 25 | int x; 26 | int min_dis = INF; 27 | for (int j = 0; j < n; j++) { 28 | if (!vis[j] && dis[j] <= min_dis) { 29 | x = j; 30 | min_dis = dis[j]; 31 | } 32 | } 33 | vis[x] = true; 34 | for (int j = 0; j < (int)G[x].size(); j++) { 35 | int y = G[x][j]; 36 | int w = GW[x][j]; 37 | dis[y] = min(dis[y], dis[x] + w); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/5_图论/3_最短路/2_Dijkstra-邻接表数组.cpp: -------------------------------------------------------------------------------- 1 | // 点最大值: MAX_N 边最大值: MAX_E 2 | // 求起点s到每个点x的最短路dis[x] 3 | const int MAX_N = "Edit"; // 点数最大值 4 | const int MAX_E = "Edit"; 5 | const int INF = 0x3F3F3F3F; 6 | int tot; 7 | int Head[MAX_N], vis[MAX_N], dis[MAX_N]; 8 | int Next[MAX_E], To[MAX_E], W[MAX_E]; 9 | void init() { 10 | tot = 0; 11 | memset(Head, -1, sizeof(Head)); 12 | } 13 | void add_edge(int u, int v, int d) { 14 | W[tot] = d; 15 | To[tot] = v; 16 | Next[tot] = Head[u]; 17 | Head[u] = tot++; 18 | } 19 | void Dijkstra(int s, int n) { 20 | memset(vis, 0, sizeof(vis)); 21 | memset(dis, 0x3F, sizeof(dis)); 22 | dis[s] = 0; 23 | for (int i = 0; i < n; i++) { 24 | int x, min_dis = INF; 25 | for (int j = 0; j < n; j++) { 26 | if (!vis[j] && dis[j] <= min_dis) { 27 | x = j; 28 | min_dis = dis[j]; 29 | } 30 | } 31 | vis[x] = 1; 32 | for (int j = Head[x]; j != -1; j = Next[j]) { 33 | int y = To[j]; 34 | dis[y] = min(dis[y], dis[x] + W[j]); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/5_图论/3_最短路/4_Dijkstra-优先队列.cpp: -------------------------------------------------------------------------------- 1 | // pair<权值, 点> 2 | // 记得初始化 3 | const int MAXN = "Edit"; 4 | const int INF = 0x3F3F3F3F; 5 | typedef pair PII; 6 | typedef vector VII; 7 | VII G[MAXN]; 8 | int vis[MAXN], dis[MAXN]; 9 | void init(int n) { 10 | for (int i = 0; i < n; i++) 11 | G[i].clear(); 12 | } 13 | void add_edge(int u, int v, int w) { 14 | G[u].push_back(make_pair(w, v)); 15 | } 16 | void Dijkstra(int s, int n) { 17 | memset(vis, 0, sizeof(vis)); 18 | memset(dis, 0x3F, sizeof(dis)); 19 | dis[s] = 0; 20 | priority_queue > q; 21 | q.push(make_pair(dis[s], s)); 22 | while (!q.empty()) { 23 | PII t = q.top(); 24 | int x = t.second; 25 | q.pop(); 26 | if (vis[x]) continue; 27 | vis[x] = 1; 28 | for (int i = 0; i < (int)G[x].size(); i++) { 29 | int y = G[x][i].second; 30 | int w = G[x][i].first; 31 | if (!vis[y] && dis[y] > dis[x] + w) { 32 | dis[y] = dis[x] + w; 33 | q.push(make_pair(dis[y], y)); 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/5_图论/3_最短路/6_SPFA.cpp: -------------------------------------------------------------------------------- 1 | // G[u] = mp(v, w) 2 | // SPFA()返回0表示存在负环 3 | const int MAXN = "Edit"; 4 | const int INF = 0x3F3F3F3F; 5 | vector > G[MAXN]; 6 | bool vis[MAXN]; 7 | int dis[MAXN]; 8 | int inqueue[MAXN]; 9 | void init(int n) { 10 | for (int i = 0; i < n; i++) 11 | G[i].clear(); 12 | } 13 | void add_edge(int u, int v, int w) { 14 | G[u].push_back(make_pair(v, w)); 15 | } 16 | bool SPFA(int s, int n) { 17 | memset(vis, 0, sizeof(vis)); 18 | memset(dis, 0x3F, sizeof(dis)); 19 | memset(inqueue, 0, sizeof(inqueue)); 20 | dis[s] = 0; 21 | queue q; // 待优化的节点入队 22 | q.push(s); 23 | while (!q.empty()) { 24 | int x = q.front(); 25 | q.pop(); 26 | vis[x] = false; 27 | for (int i = 0; i < G[x].size(); i++) { 28 | int y = G[x][i].first; 29 | int w = G[x][i].second; 30 | if (dis[y] > dis[x] + w) { 31 | dis[y] = dis[x] + w; 32 | if (!vis[y]) { 33 | q.push(y); 34 | vis[y] = true; 35 | if (++inqueue[y] >= n) return 0; 36 | } 37 | } 38 | } 39 | } 40 | return 1; 41 | } 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Yue Gao 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/2_数学/7_莫比乌斯反演/2_n个数中互质数对数.cpp: -------------------------------------------------------------------------------- 1 | // 有n个数($n\leq 10^5$),问这n个数中互质的数的对数 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | long long ans; 7 | const int MAXN = 1e5 + 1; 8 | int n, x, prime[MAXN], _max, b[MAXN], tot, mu[MAXN]; 9 | bool check[MAXN]; 10 | void calmu() { 11 | mu[1] = 1; 12 | for (int i = 2; i < MAXN; i++) { 13 | if (!check[i]) { 14 | prime[tot++] = i; 15 | mu[i] = -1; 16 | } 17 | for (int j = 0; j < tot; j++) { 18 | if (i * prime[j] >= MAXN) break; 19 | check[i * prime[j]] = true; 20 | if (i % prime[j] == 0) { 21 | mu[i * prime[j]] = 0; 22 | break; 23 | } else { 24 | mu[i * prime[j]] = -mu[i]; 25 | } 26 | } 27 | } 28 | } 29 | int main() { 30 | calmu(); 31 | while (scanf("%d", &n) == 1) { 32 | memset(b, 0, sizeof(b)); 33 | _max = 0; ans = 0; 34 | for (int i = 0; i < n; i++) { 35 | scanf("%d", &x); 36 | if (x > _max) _max = x; 37 | b[x]++; 38 | } 39 | int cnt; 40 | for (int i = 1; i <= _max; i++) { 41 | cnt = 0; 42 | for (long long j = i; j <= _max; j += i) 43 | cnt += b[j]; 44 | ans += 1LL * mu[i] * cnt * cnt; 45 | } 46 | printf("%lld\n", (ans - b[1]) / 2); 47 | } 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /src/4_数据结构/2_线段树/3_区间更新-区间查询.cpp: -------------------------------------------------------------------------------- 1 | // seg[rt]用于存放懒惰标记,注意PushDown时标记的传递 2 | const int maxn = 101010; 3 | int seg[maxn << 2], sum[maxn << 2]; 4 | void PushUp(int rt) { 5 | sum[rt] = sum[lson] + sum[rson]; 6 | } 7 | void PushDown(int rt, int m) { 8 | if (seg[rt] == 0) return; 9 | seg[lson] += seg[rt]; 10 | seg[rson] += seg[rt]; 11 | sum[lson] += seg[rt] * (m - (m >> 1)); 12 | sum[rson] += seg[rt] * (m >> 1); 13 | seg[rt] = 0; 14 | } 15 | void build(int l, int r, int rt) { 16 | seg[rt] = 0; 17 | if (l == r) {scanf("%lld", &sum[rt]); return;} 18 | int m = (l + r) >> 1; 19 | build(Lson); build(Rson); 20 | PushUp(rt); 21 | } 22 | void update(int L, int R, int add, int l, int r, int rt) { 23 | if (L <= l && r <= R) { 24 | seg[rt] += add; 25 | sum[rt] += add * (r - l + 1); 26 | return; 27 | } 28 | PushDown(rt, r - l + 1); 29 | int m = (l + r) >> 1; 30 | if (L <= m) update(L, R, add, Lson); 31 | if (m < R) update(L, R, add, Rson); 32 | PushUp(rt); 33 | } 34 | int query(int L, int R, int l, int r, int rt) { 35 | if (L <= l && r <= R) return sum[rt]; 36 | PushDown(rt, r - l + 1); 37 | int m = (l + r) >> 1, ret = 0; 38 | if (L <= m) ret += query(L, R, Lson); 39 | if (m < R) ret += query(L, R, Rson); 40 | return ret; 41 | } 42 | -------------------------------------------------------------------------------- /CheatSheet.sty: -------------------------------------------------------------------------------- 1 | % CheatSheet.sty 2 | % LaTeX style file for ACM-ICPC Cheat Sheet 3 | % By Lodour (jjmangogao@gmail.com) 4 | % Version: 2017.11.5 5 | % LaTeX style file for ACM-ICPC Cheat Sheet. 6 | % load after article.cls 7 | 8 | % 中文显示 9 | \usepackage{xeCJK} 10 | \setCJKmainfont[ 11 | BoldFont=STSongti-SC-Black, 12 | ItalicFont=AdobeFangsongStd-Regular 13 | ]{AdobeSongStd-Light} 14 | %\setCJKsansfont{STHeiti} 15 | %\setCJKmonofont{STKaiti} 16 | 17 | % 数学公式扩展 18 | \usepackage{amsmath, amsthm} 19 | 20 | % 目录等级 21 | \usepackage{shorttoc} 22 | \setcounter{tocdepth}{3} 23 | 24 | % 代码高亮 25 | \usepackage[cache=false]{minted} 26 | \setminted{frame=single,mathescape,breaklines,tabsize=4} 27 | 28 | % 页边距 29 | \usepackage{geometry} 30 | \geometry{bottom=1in, top=1in} 31 | \geometry{left=1.25in, right=1.25in} 32 | 33 | % 插入图片 34 | \usepackage{graphicx} 35 | 36 | % 环境定义 37 | \newtheorem{theorem}{定理}[section] 38 | \newtheorem{defination}{定义}[section] 39 | \newtheorem{corollary}{推论}[section] 40 | 41 | % 特殊命令 42 | \newcommand{\HRule}{\rule{\linewidth}{0.5mm}} 43 | 44 | % 名词翻译 45 | \renewcommand{\today}{\number\year 年 \number\month 月 \number\day 日} 46 | \renewcommand{\contentsname}{目\qquad 录} 47 | \renewcommand\figurename{图} 48 | -------------------------------------------------------------------------------- /src/1_头文件模板/1_C++.cpp: -------------------------------------------------------------------------------- 1 | #include // c++0x only 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 | #include 15 | #include 16 | #include 17 | #include 18 | using namespace std; 19 | #define REP(i,x) for(int i = 0; i < (x); i++) 20 | #define DEP(i,x) for(int i = (x) - 1; i >= 0; i--) 21 | #define FOR(i,x) for(__typeof(x.begin())i=x.begin(); i!=x.end(); i++) 22 | #define CLR(a,x) memset(a, x, sizeof(a)) 23 | #define MO(a,b) (((a)%(b)+(b))%(b)) 24 | #define ALL(x) (x).begin(), (x).end() 25 | #define SZ(v) ((int)v.size()) 26 | #define UNIQUE(v) sort(ALL(v)); v.erase(unique(ALL(v)), v.end()) 27 | #define out(x) cout << #x << ": " << x << endl; 28 | #define fastcin ios_base::sync_with_stdio(0);cin.tie(0); 29 | typedef long long ll; 30 | typedef unsigned long long ull; 31 | typedef pair PII; 32 | typedef vector VI; 33 | #define INF 0x3f3f3f3f 34 | #define MOD 1000000007 35 | #define EPS 1e-8 36 | #define MP(x,y) make_pair(x,y) 37 | #define MT(x,y...) make_tuple(x,y) // c++0x only 38 | #define PB(x) push_back(x) 39 | #define IT iterator 40 | #define X first 41 | #define Y second 42 | -------------------------------------------------------------------------------- /src/5_图论/5_欧拉回路/2_求解.cpp: -------------------------------------------------------------------------------- 1 | #define MAXN 200 2 | struct stack { 3 | int top, node[MAXN]; 4 | } s; 5 | 6 | int G[MAXN][MAXN]; // 邻接矩阵 7 | int n; // 顶点个数 8 | 9 | void dfs(int x) { 10 | int i; 11 | s.node[++s.top] = x; 12 | for (int i = 0; i < n; i++) 13 | if (G[i][x] > 0) { 14 | G[i][x] = G[x][i] = 0; 15 | dfs(i); 16 | break; 17 | } 18 | } 19 | void Fleury(int x) { 20 | int i, b; 21 | s.node[s.top = 0] = x; 22 | while (s.top >= 0) { 23 | b = 0; 24 | for (int i = 0; i < n; i++) 25 | if (G[s.node[s.top]][i] > 0) { 26 | b = 1; 27 | break; 28 | } 29 | if (b == 0) { 30 | printf("%d ", s.node[s.top] + 1); 31 | s.top--; 32 | } 33 | else { 34 | s.top--; 35 | dfs(s.node[s.top + 1]); 36 | } 37 | } 38 | printf("\n"); 39 | } 40 | 41 | int main() { 42 | int i, j; 43 | int m, s, t; // 边数,读入的边的起点和终点 44 | int degree, num, start; // 每个顶点的度、奇度顶点个数、欧拉回路的起点 45 | scanf("%d%d", &n, &m); 46 | set(G, 0); 47 | for (i = 0; i < m; i++) { 48 | scanf("%d%d", &s, &t) 49 | G[s - 1][t - 1] = G[t - 1][s - 1] = 1; 50 | } 51 | num = 0; start = 0; 52 | for (i = 0; i < n; i++) { 53 | degree = 0; 54 | for (j = 0; j < n; j++) 55 | degree += G[i][j]; 56 | if (degree & 1) { 57 | start = i; 58 | num++; 59 | } 60 | } 61 | if (num == 0 || num == 2) Fleury(start); 62 | else puts("No Euler path"); 63 | return 0; 64 | } -------------------------------------------------------------------------------- /src/6_计算几何/1_定义.cpp: -------------------------------------------------------------------------------- 1 | #define eps 1e-8 2 | #define pi M_PI 3 | #define zero(x) ((fabs(x) 2 | #include 3 | #include 4 | using namespace std; 5 | const int N = 100100; 6 | struct Point { 7 | double x, y; 8 | }; 9 | int n; 10 | Point p[N], tmp[N]; 11 | 12 | bool cmp(Point a, Point b) {return a.x == b.x ? a.y < b.y : a.x < b.x;} 13 | bool cmpy(Point a, Point b) {return a.y < b.y;} 14 | double dis(Point a, Point b) { 15 | double dx = a.x - b.x; 16 | double dy = a.y - b.y; 17 | return sqrt(dx * dx + dy * dy); 18 | } 19 | double solve(int l, int r) { 20 | double d = 1e20; 21 | if (l == r) return d; 22 | if (l + 1 == r) return dis(p[l], p[r]); 23 | int mid = l + r >> 1; 24 | double d1 = solve(l, mid); 25 | double d2 = solve(mid + 1, r); 26 | d = min(d1, d2); 27 | int k = 0; 28 | for (int i = l; i <= r; i++) 29 | if (fabs(p[i].x - p[mid].x) <= d) 30 | tmp[k++] = p[i]; 31 | sort(tmp, tmp + k, cmpy); 32 | for (int i = 0; i < k; i++) 33 | for (int j = i + 1; j < k; j++) { 34 | if (tmp[j].y - tmp[i].y > d) break; 35 | d = min(d, dis(tmp[i], tmp[j])); 36 | } 37 | return d; 38 | } 39 | int main() { 40 | while (scanf("%d", &n) && n != 0) { 41 | for (int i = 0; i < n; i++) 42 | scanf("%lf %lf", &p[i].x, &p[i].y); 43 | sort(p, p + n, cmp); 44 | printf("%.2lf\n", solve(0, n - 1) / 2); 45 | } 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /src/4_数据结构/3_字典树.cpp: -------------------------------------------------------------------------------- 1 | struct Node { 2 | char c; 3 | Node* next[26]; 4 | Node(char cc) { 5 | c = cc; 6 | REP(i, 26)next[i] = NULL; 7 | } 8 | ~Node() { 9 | REP(i, 26) if (next[i] != NULL) { 10 | next[i]->~Node(); 11 | delete next[i]; 12 | next[i] = NULL; 13 | } 14 | } 15 | bool empty() { 16 | REP(i, 26)if (next[i])return 0; 17 | return 1; 18 | } 19 | }; 20 | 21 | class Trie { 22 | public: 23 | Node *rt; 24 | Trie() { 25 | rt = new Node('*'); 26 | } 27 | ~Trie() { 28 | rt->~Node(); 29 | } 30 | void insert(char s[]) { 31 | Node *p = rt; 32 | for (int i = 0; s[i]; i++) { 33 | int d = s[i] - 'A'; 34 | if (!p->next[d]) 35 | p->next[d] = new Node(s[i]); 36 | p = p->next[d]; 37 | } 38 | } 39 | int find(char s[]) { 40 | Node *p = rt; 41 | for (int i = 0; s[i]; i++) { 42 | int d = s[i] - 'A'; 43 | if (!p->next[d]) return 0; 44 | p = p->next[d]; 45 | } 46 | return 1; 47 | } 48 | void remove(char s[]) { 49 | stack st; 50 | Node *pp = rt; 51 | for (int i = 0; s[i]; i++) { 52 | int d = s[i] - 'A'; 53 | if (!pp->next[d]) return; 54 | st.push(pp); 55 | pp = pp->next[d]; 56 | } 57 | pp->~Node(); 58 | while (!st.empty()) { 59 | Node *p = st.top(); st.pop(); 60 | p->next[pp->c - 'A'] = NULL; 61 | pp = p; 62 | bool f = 1; 63 | REP(i, 26) if (p->next[i]) f = 0; 64 | if (f) { 65 | p->~Node(); 66 | if (!st.empty())st.top()->next[p->c - 'A'] = NULL; 67 | } 68 | else break; 69 | } 70 | if (rt == NULL) rt = new Node('*'); 71 | } 72 | }; 73 | -------------------------------------------------------------------------------- /core.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | import logging 3 | import re 4 | from pathlib import Path 5 | 6 | import settings 7 | 8 | 9 | class Generator(object): 10 | PATTERN = re.compile(r'^\w+?_(?P.+?)(\.(?P\w+)){0,1}$') 11 | 12 | def __init__(self): 13 | self.content = [] 14 | 15 | def populate(self, folder=None, depth=0): 16 | """ 17 | 输出文档内容 18 | :param folder: 模板根目录 19 | :param depth: 遍历深度 20 | :return: str 21 | """ 22 | if folder is None: 23 | folder = Path('./src') 24 | 25 | # 如果folder内只有一个项目,则不输出子标题 26 | unique = False 27 | if len([i for i in folder.iterdir() if self.PATTERN.match(i.name)]) == 1: 28 | unique = True 29 | 30 | for item in folder.iterdir(): 31 | match = self.PATTERN.search(item.name) 32 | 33 | if match is None: 34 | logging.warning('Unknown file skipped: %r' % item.absolute()) 35 | continue 36 | 37 | name, lang = match.group('name'), match.group('lang') 38 | if not unique: 39 | self.populate_section(name, depth) 40 | if item.is_dir(): 41 | self.populate(item, depth + 1 - unique) 42 | if item.is_file(): 43 | self.populate_file(name, lang, item.as_posix(), depth + 1 - unique) 44 | 45 | return '\n'.join(self.content) 46 | 47 | def populate_section(self, caption, depth): 48 | """ 49 | 输出段落 50 | :param caption: 标题 51 | :param depth: 遍历深度 52 | :return: str 53 | """ 54 | line = ''.join([' ' * depth, '\\', 'sub' * depth, 'section{%s}' % caption]) 55 | self.content.append(line) 56 | 57 | def populate_file(self, caption, suffix, path, depth): 58 | """ 59 | 输出文件 60 | :param caption: 标题 61 | :param suffix: 后缀名 62 | :param path: 相对路径 63 | :param depth: 遍历深度 64 | :return: list 65 | """ 66 | if suffix.lower() in settings.INPUT_TYPE: 67 | line = ''.join([' ' * depth, '\\input{%s}' % path]) 68 | self.content.append(line) 69 | if suffix.lower() in settings.CODE_TYPE: 70 | line = ''.join([' ' * depth, '\\inputminted{%s}{%s}' % (suffix, path)]) 71 | self.content.append(line) 72 | -------------------------------------------------------------------------------- /src/3_字符串/3_AC自动机.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | #define rep(i,a,n) for (int i=a;igo, 0, sizeof(p->go)); 14 | p->fail = p->fa = NULL; p->fg = 0; 15 | return p; 16 | } 17 | void init() { cur = pool; root = newnode();} 18 | node* append(node *p, int w) { 19 | if (!p->go[w]) p->go[w] = newnode(), p->go[w]->fa = p; 20 | return p = p->go[w]; 21 | } 22 | void build() { 23 | int t = 1; 24 | q[0] = root; 25 | rep(i, 0, t) rep(j, 0, AC_SIGMA) if (q[i]->go[j]) { 26 | node *v = q[i]->go[j], *p = v->fa->fail; 27 | while (p && !p->go[j]) p = p->fail; 28 | if (p) v->fail = p->go[j]; else v->fail = root; 29 | q[t++] = q[i]->go[j]; 30 | } else { 31 | node *p = q[i]->fail; 32 | while (p && !p->go[j]) p = p->fail; 33 | if (p) q[i]->go[j] = p->go[j]; else q[i]->go[j] = root; 34 | } 35 | } 36 | int query(char s[]) { 37 | node *p = root; 38 | int res = 0; 39 | for (int i = 0; s[i]; i++) { 40 | p = p->go[s[i] - 'a']; 41 | node *v = p; 42 | while (v != root) { 43 | res += v->fg; 44 | v->fg = 0; 45 | v = v->fail; 46 | } 47 | } 48 | return res; 49 | } 50 | } T; 51 | typedef AC_automaton::node ACnode; 52 | 53 | 54 | const int MAXN = 1000000 + 1000; 55 | char txt[MAXN]; 56 | 57 | int main() { 58 | #ifdef MANGOGAO 59 | freopen("data.in", "r", stdin); 60 | #endif 61 | 62 | int t; 63 | scanf("%d", &t); 64 | while (t--) { 65 | int n; 66 | scanf("%d", &n); 67 | T.init(); 68 | char s[55]; 69 | rep(i, 0, n) { 70 | ACnode *p = T.root; 71 | scanf("%s", s); 72 | for (int j = 0; s[j]; j++) 73 | p = T.append(p, s[j] - 'a'); 74 | p->fg++; 75 | } 76 | T.build(); 77 | scanf("%s", txt); 78 | printf("%d\n", T.query(txt)); 79 | } 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /src/2_数学/9_相关公式.tex: -------------------------------------------------------------------------------- 1 | 约数定理:若$n=\prod_{i=1}^kp_i^{a_i}$,则 2 | 3 | 1.约数个数$f(n)=\prod_{i=1}^k(a_i+1)$ 4 | 5 | 2.约数和$g(n)=\prod_{i=1}^k(\sum_{j=0}^{a_i}p_i^j)$ 6 | 7 | 小于$n$且互素的数之和为$n\varphi(n)/2$ 8 | 9 | 若$gcd(n,i)=1$,则$gcd(n,n-i)=1(1\leq i\leq n)$ 10 | 11 | 错排公式:$D(n)=(n-1)(D(n-2)+D(n-1))=\sum_{i=2}^n\frac{(-1)^kn!}{k!}=[\frac{n!}{e}+0.5]$ 12 | 13 | 威尔逊定理:$p\ is\ prime\ \Rightarrow (p-1)!\equiv-1(mod\ p)$ 14 | 15 | 欧拉定理:$gcd(a,n)=1\Rightarrow a^{\varphi(n)}\equiv1(mod\ n)$ 16 | 17 | 欧拉定理推广:$gcd(n,p)=1\Rightarrow a^n\equiv a^{n\%\varphi(p)}(mod\ p)$ 18 | 19 | 素数定理:对于不大于n的素数个数$\pi(n)$,$\lim\limits_{n\to\infty}\pi(n)=\frac{n}{\ln n}$ 20 | 21 | 位数公式:正整数$x$的位数$N=log10(n)+1$ 22 | 23 | 斯特灵公式$n!\approx\sqrt{2\pi n}(\frac{n}{e})^n$ 24 | 25 | 设$a>1,m,n>0$,则$gcd(a^m-1,a^n-1)=a^{gcd(m,n)}-1$ 26 | 27 | 设$a>b,gcd(a,b)=1$,则$gcd(a^m-b^m,a^n-b^n)=a^{gcd(m,n)}-b^{gcd(m,n)}$ 28 | 29 | $$ 30 | G=gcd(C_n^1,C_n^2,...,C_n^{n-1})= 31 | \begin{cases} 32 | n, & \text{$n$ is prime} \\ 33 | 1, & \text{$n$ has multy prime factors} \\ 34 | p, & \text{$n$ has single prime factor $p$} 35 | \end{cases} 36 | $$ 37 | 38 | $gcd(Fib(m),Fib(n))=Fib(gcd(m,n))$ 39 | 40 | 若$gcd(m,n)=1$,则: 41 | 42 | 1.最大不能组合的数为$m*n-m-n$ 43 | 44 | 2.不能组合数个数$N=\frac{(m-1)(n-1)}{2}$ 45 | 46 | $(n+1)lcm(C_n^0,C_n^1,...,C_n^{n-1},C_n^{n})=lcm(1,2,...,n+1)$ 47 | 48 | 若$p$为素数,则$(x+y+...+w)^p\equiv x^p+y^p+...+w^p(mod\ p)$ 49 | 50 | 卡特兰数:1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012 51 | 52 | $h(0)=h(1)=1,h(n)=\frac{(4n-2)h(n-1)}{n+1}=\frac{C_{2n}^n}{n+1}=C_{2n}^n-C_{2n}^{n-1}$ 53 | 54 | $$ 55 | a_{n+m}=\sum_{i=0}^{m-1}b_ia_{n+i}\Rightarrow 56 | \left( 57 | \begin{matrix} 58 | a_{n+m} \\\\ 59 | a_{n+m-1} \\\\ 60 | \vdots \\\\ 61 | a_{n+1} \\\\ 62 | \end{matrix} 63 | \right) 64 | = 65 | \left( 66 | \begin{matrix} 67 | b_{m-1} && \cdots && b_1 && b_0 \\\\ 68 | 1 && \cdots && 0 && 0 \\\\ 69 | \vdots && \ddots && \vdots && \vdots \\\\ 70 | 0 && \cdots && 1 && 0 \\\\ 71 | \end{matrix} 72 | \right) 73 | \left( 74 | \begin{matrix} 75 | a_{n+m-1} \\\\ 76 | a_{n+m-2} \\\\ 77 | \vdots \\\\ 78 | a_n \\\\ 79 | \end{matrix} 80 | \right) 81 | $$ 82 | 83 | $$ 84 | a_{n+m}=\sum_{i=0}^{m-1}b_ia_{n+i}+c\Rightarrow 85 | \left( 86 | \begin{matrix} 87 | a_{n+m} \\\\ 88 | a_{n+m-1} \\\\ 89 | \vdots \\\\ 90 | a_{n+1} \\\\ 91 | 1 \\\\ 92 | \end{matrix} 93 | \right) 94 | = 95 | \left( 96 | \begin{matrix} 97 | b_{m-1} && \cdots && b_1 && b_0 && c \\\\ 98 | 1 && \cdots && 0 && 0 && 0 \\\\ 99 | \vdots && \ddots && \vdots && \vdots && \vdots \\\\ 100 | 0 && \cdots && 1 && 0 && 0 \\\\ 101 | 0 && \cdots && 0 && 0 && 1 \\\\ 102 | \end{matrix} 103 | \right) 104 | \left( 105 | \begin{matrix} 106 | a_{n+m-1} \\\\ 107 | a_{n+m-2} \\\\ 108 | \vdots \\\\ 109 | a_n \\\\ 110 | 1 \\\\ 111 | \end{matrix} 112 | \right) 113 | $$ -------------------------------------------------------------------------------- /src/6_计算几何/3_多边形/5_小结.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #define MAXN 1000 4 | #define offset 10000 5 | #define eps 1e-8 6 | #define zero(x) (((x)>0?(x):-(x))eps?1:((x)<-eps?2:0)) 8 | struct point{double x,y;}; 9 | struct line{point a,b;}; 10 | 11 | double xmult(point p1,point p2,point p0){ 12 | return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y); 13 | } 14 | 15 | // 判定凸多边形,顶点按顺时针或逆时针给出,允许相邻边共线 16 | int is_convex(int n,point* p){ 17 | int i,s[3]={1,1,1}; 18 | for (i=0;ieps){ 124 | t=barycenter(p[0],p[i],p[i+1]); 125 | ret.x+=t.x*t2; 126 | ret.y+=t.y*t2; 127 | t1+=t2; 128 | } 129 | if (fabs(t1)>eps) 130 | ret.x/=t1,ret.y/=t1; 131 | return ret; 132 | } 133 | --------------------------------------------------------------------------------