- 1、辗转相除法求最大公约数
int gcd(int a,int b) { return b == 0?a:gcd(b,a%b); }
- 2、最大公约数
int lcm(int a,int b) { return a/gcd(a,b)*b; //先除后乘防止a*b溢出 }
- 3、拓展欧几里德算法
void extgcd(__int64 a,__int64 b,__int64 &x,__int64 &y) { if (!b) { x = 1; y = 0; } else { extgcd(b,a%b,y,x); y -= x*(a/b); } }
- 4、求区间[m,n]内的素数( 埃氏筛选法)
int m = sqrt(n+0.5); memset(vis,0,sizeof(vis)); for (int i = 2; i <= m; i++) { if (!vis[i]) { for (int j = i*i; j <= n; j += i) { vis[j] = 1; } } } 版本二O(nloglogn) int p = 0; memset(is_prime,true,sizeof(is_prime)); is_prime[0] = is_prime[1] = false; for(int i = 2; i <= MAX; i++) { if (is_prime[i]) { prime[p++] = i; for (int j = 2 * i; j <= MAX; j += i) { is_prime[j] = false; } } }
- 5、无平方因子的数
对于不超过√m 的所有素数p,筛选区间[n,m]内p² 的所有倍数
- 6、快速乘
LL mod_multi(LL x,LL y,LL mod) //拆分成y个x相加 { LL res = 0; while (y) { if (y&1) { res += x; while (res >= mod) res -= mod; } x += x; while (x >= mod) x -= mod; y >>= 1; } return res; }
- 7、快速幂
LL mod_pow(LL x,LL n,LL mod) { LL res = 1; while (n > 0) { if (n&1) { res = mod_mulit(res,x,mod); // res = res*x%mod; } x = mod_multi(x,x,mod); //x = x*x%mod; n >>= 1; } return res; }
- 8、二分查找
// binsearch_min 返回key(可能有重复)第一次出现的下标,如无return -1 int binsearch_min(int * arr, int lef, int rig, int key) { if(!arr) return -1; int left = lef, right = rig; while(left < right) { int mid = left + ((right-left)>>1); if(arr[mid] < key) { left = mid+1; } else { right = mid; } } if(arr[left] == key) return left; return -1; } // binsearch_max 返回key(可能有重复)最后一次出现的下标,如无return -1 int binsearch_max(int * arr, int lef, int rig, int key) { if(!arr) return -1; int left = lef, right = rig; while(left < right -1) { int mid = left + ((right-left)>>1); if(arr[mid] <= key) { left = mid; } else { right = mid; } } if(arr[right] == key) // 找max,先判断right { return right; } else if(arr[left] == key) { return left; } else return -1; }
- 9、并查集
void init() { memset(father,0,sizeof(father)); memset(rk,0,sizeof(rk)); for (int i = 0; i <= N; i++) { father[i] = i; } } int find(int x) { int r = x; while (father[r] != r) { r = father[r]; } int i = x,j; while (i != r) //路径压缩 { j = father[i]; father[i] = r; i = j; } return r; } /* int find(int x) { return father[x] == x?father[x]:father[x] = find(father[x]); } */ void unite(int x,int y) { int fx,fy; fx = find(x); fy = find(y); if (fx == fy) return; if (rk[fx] < rk[fy]) { father[fx] = fy; } else { father[fy] = fx; if (rk[fx] == rk[fy]) { rk[fx]++; } } }
- 10、生成1~n的排列
void permutation(int n,int *A,int cur) { if (cur == n) //递归边界 { for (int i = 0;i < n;i++) printf("%d ",A[i]); printf(" "); } else for (int i = 1;i <= n;i++) //尝试在A[cur}中填各种整数i { int ok = 1; for (int j = 0;j < cur;j++) if (A[j] == i) ok = 0; //如果i已经在A[0]~A[cur-1]出现过,则不能再选 if (ok) { A[cur] = i; permutation(n,A,cur+1); //递归调用 } } }
- 11、生成可重集的排列
void permutation(int n,int *P,int *A,int cur) //输入数组P,并按字典序输出数组A各元素的所有全排列 { if (cur == n) { for (int i = 0; i < n; i++) printf("%d ",A[i]); printf(" "); } else for (int i = 0; i < n; i++) { if (!i || P[i] != P[i-1]) { int c1 = 0,c2 = 0; for (int j = 0; j < cur; j++) if (A[j] == P[i]) c1++; for (int j = 0; j < n; j++) if (P[i] == P[j]) c2++; if (c1 < c2) { A[cur] = P[i]; permutation(n,P,A,cur+1); } } } }
- 12、强连通分量的targin算法
/* 寻找有向图强连通分量的tarjan算法 * index表示的就是时间戳 * scc_cnt 表示强连通分量的个数 * belong[u] 表示结点u属于哪一个强连通分量 * inst[u] 表示结点u是否仍然在栈中 * st[] 和 top 分别表示栈和栈顶位置 *index = scc_cnt = top = 0*/ void targin(int u) { int v; dfn[u] = low[u] = ++index; st[++top] = u; inst[u] = 1; for (int i = head[u];i != -1;i = edge[i].next) { v = edge[i].v; if (!dfn[v]) { targin(v); low[u] = min(low[u],low[v]); } else if (inst[v]) low[u] = min(low[u],dfn[v]); } if (low[u] == dfn[u]) { scc_cnt++; do { v = st[top--]; inst[v] = 0; belong[v] = scc_cnt; } while (u != v); } }
- 13、SBT
/* * tree[x].left 表示以 x 为节点的左儿子 * tree[x].right 表示以 x 为节点的右儿子 * tree[x].size 表示以 x 为根的节点的个数(大小) */ struct SBT { int key,left,right,size; } tree[10010]; int root = 0,top = 0; void left_rot(int &x) // 左旋 { int y = tree[x].right; if (!y) return; tree[x].right = tree[y].left; tree[y].left = x; tree[y].size = tree[x].size; tree[x].size = tree[tree[x].left].size + tree[tree[x].right].size + 1; x = y; } void right_rot(int &x) //右旋 { int y = tree[x].left; if (!y) return; tree[x].left = tree[y].right; tree[y].right = x; tree[y].size = tree[x].size; tree[x].size = tree[tree[x].left].size + tree[tree[x].right].size + 1; x = y; } void maintain(int &x,bool flag) //维护SBT状态 { if (!x) return; if (flag == false) //左边 { if(tree[tree[tree[x].left].left].size > tree[tree[x].right].size)//左孩子的左孩子大于右孩子 right_rot(x); else if (tree[tree[tree[x].left].right].size > tree[tree[x].right].size) //左孩子的右孩子大于右孩子 { left_rot(tree[x].left); right_rot(x); } else return; } else //右边 { if(tree[tree[tree[x].right].right].size > tree[tree[x].left].size)//右孩子的右孩子大于左孩子 left_rot(x); else if(tree[tree[tree[x].right].left].size > tree[tree[x].left].size) //右孩子的左孩子大于左孩子 { right_rot(tree[x].right); left_rot(x); } else return; } maintain(tree[x].left,false); maintain(tree[x].right,true); maintain(x,true); maintain(x,false); } void insert(int &x,int key) //插入 { if (x == 0) { x = ++top; tree[x].left = 0; tree[x].right = 0; tree[x].size = 1; tree[x].key = key; } else { tree[x].size++; if(key < tree[x].key) insert(tree[x].left,key); else insert(tree[x].right,key);//相同元素可插右子树 maintain(x,key >= tree[x].key); } } int remove(int &x,int key) //利用后继删除 { tree[x].size--; if(key > tree[x].key) remove(tree[x].right,key); else if(key < tree[x].key) remove(tree[x].left,key); else if(tree[x].left !=0 && !tree[x].right) //有左子树,无右子树 { int tmp = x; x = tree[x].left; return tmp; } else if(!tree[x].left && tree[x].right != 0) //有右子树,无左子树 { int tmp = x; x = tree[x].right; return tmp; } else if(!tree[x].left && !tree[x].right) //无左右子树 { int tmp = x; x = 0; return tmp; } else //左右子树都有 { int tmp = tree[x].right; while(tree[tmp].left) tmp = tree[tmp].left; tree[x].key = tree[temp].key; remove(tree[x].right,tree[tmp].key); } } int getmin(int x) //求最小值 { while(tree[x].left) x = tree[x].left; return tree[x].key; } int getmax(int x) //求最大值 { while(tree[x].right) x = tree[x].right; return tree[x].key; } int pred(int &x,int y,int key) //前驱,y初始前驱,从0开始, 最终要的是返回值的key值 { if(x == 0) return y; if(key > tree[x].key) return pred(tree[x].right,x,key); else return pred(tree[x].left,y,key); } int succ(int &x,int y,int key) //后继,同上 { if(x == 0) return y; if(key < tree[x].key) return succ(tree[x].left,x,key); else return succ(tree[x].right,y,key); } int select(int &x,int k) //查找第k小的数 { int r = tree[tree[x].left].size + 1; if(r == k) return tree[x].key; else if(r < k) return select(tree[x].right,k - r); else return select(tree[x].left,k); } int rank(int &x,int key) //key排第几 { if(key < tree[x].key) { return rank(tree[x].left,key); } else if(key > tree[x].key) return rank(tree[x].right,key) + tree[tree[x].left].size + 1; else return tree[tree[x].left].size + 1; }
- 14、关闭同步
ios::sync_with_stdio(false); cin.tie(NULL);