ACM常用模板 最大公约数欧拉函数
计算最大公约数的欧拉算法

计算最大公约数的欧拉算法
欧拉算法,也称为辗转相除法,是一种计算最大公约数的常用方法。
它的基本思想是通过不断地用较小数去除较大数,直到两个数相等为止,这个相等的数就是最大公约数。
欧拉算法的具体步骤如下:
1. 选取两个正整数a和b,其中a>b。
2. 用b去除a,得到余数r,如果r等于0,则b就是最大公约数。
3. 如果r不等于0,则用b去除r,得到余数r1。
4. 如果r1等于0,则r就是最大公约数。
5. 如果r1不等于0,则继续用r去除r1,得到余数r2。
6. 重复上述步骤,直到余数为0为止。
欧拉算法的优点是简单易懂,计算速度快,适用于大数的计算。
但是,它也有一些缺点,比如当两个数相差较大时,需要进行多次除法运算,计算量较大。
除了欧拉算法,还有其他计算最大公约数的方法,比如质因数分解法、辗转相减法等。
不同的方法适用于不同的情况,需要根据具体情况选择合适的方法。
欧拉算法是一种简单有效的计算最大公约数的方法,它的应用范围广泛,可以用于数学、计算机科学等领域。
在实际应用中,我们可以根据具体情况选择不同的方法,以达到最优的计算效果。
求欧拉函数

求欧拉函数求欧拉函数是数论中的一个重要问题,它可以帮助我们计算整数集合中与某个给定整数n互质的数的个数。
欧拉函数的定义是:对于任意正整数n,欧拉函数φ(n)表示小于或等于n的正整数中与n互质的数的个数。
欧拉函数的计算方法有多种,下面我将介绍其中两种常用的方法。
一、分解质因数法欧拉函数的一个重要性质是:若n是质数p的k次幂,则φ(p^k) = p^k - p^(k-1)。
根据这个性质,我们可以用分解质因数的方法来计算φ(n)。
具体步骤如下:1. 将n进行质因数分解,得到n = p1^k1 * p2^k2 * ... * pm^km 的形式,其中p1、p2、...、pm是不同的质数,k1、k2、...、km 是对应的幂次。
2. 根据性质φ(p^k) = p^k - p^(k-1),计算每个质因数的欧拉函数值,即φ(p1^k1)、φ(p2^k2)、...、φ(pm^km)。
3. 最后,将所有质因数的欧拉函数值相乘,即可得到φ(n)的值。
例如,对于n = 12,我们可以将其分解为2^2 * 3^1。
根据性质φ(p^k) = p^k - p^(k-1),我们可以计算出φ(2^2) = 2^2 - 2^1 = 2,φ(3^1) = 3^1 - 3^0 = 2。
最后,将这两个值相乘,得到φ(12) = 2 * 2 = 4。
二、递推法欧拉函数还可以通过递推法来计算,具体步骤如下:1. 初始化φ(1) = 1,φ(i) = i-1(i>1)。
2. 从i = 2开始,依次计算φ(i)的值。
3. 对于每个i,遍历所有小于i且与i互质的数j,将φ(j)的值加到φ(i)上。
4. 最后得到的φ(n)即为所求。
例如,对于n = 12,我们可以按照上述步骤进行计算。
首先初始化φ(1) = 1,φ(2) = 2-1 = 1,φ(3) = 3-1 = 2,φ(4) = 4-1 = 3。
然后,计算φ(5)时,遍历所有小于5且与5互质的数,发现只有1和2满足条件,所以将它们对应的φ值加到φ(5)上,即φ(5) = φ(1) + φ(2) = 1 + 1 = 2。
(2020年编辑)ACM必做50题的解题-数论

poj 1061 青蛙的约会这题用的是解线性同余方程的方法,之前没接触到过,搜索资料后看到一个人的博客里面讲的很好就拷贝过来了。
内容如下:对于方程:ax≡b(mod m),a,b,m都是整数,求解x 的值,这个就是线性同余方程。
符号说明:mod表示:取模运算ax≡b(mod m)表示:(ax - b) mod m = 0,即同余gcd(a,b)表示:a和b的最大公约数求解ax≡b(mod n)的原理:对于方程ax≡b(mod n),存在ax + by = gcd(a,b),x,y是整数。
而ax≡b(mod n)的解可以由x,y来堆砌。
具体做法如下:第一个问题:求解gcd(a,b)定理一:gcd(a,b) = gcd(b,a mod b)欧几里德算法int Euclid(int a,int b){if(b == 0)return a;elsereturn Euclid(b,mod(a,b));}附:取模运算int mod(int a,int b){if(a >= 0)return a % b;elsereturn a % b + b;}第二个问题:求解ax + by = gcd(a,b)定理二:ax + by = gcd(a,b)= gcd(b,a mod b) = b * x' + (a mod b) * y'= b * x' + (a - a / b * b) * y'= a * y' + b * (x' - a / b * y')= a * x + b * y则:x = y'y = x' - a / b * y'以上内容转自/redcastle/blog/item/934b232dbc40d336349bf7e4.html由这个可以得出扩展的欧几里德算法:int exGcd(int a, int b, int &x, int &y) {if(b == 0){x = 1;y = 0;return a;}int r = exGcd(b, a % b, x, y);int t = x;x = y;y = t - a / b * y;return r;}代码:#include<iostream>#include<cstdlib>#include<cstring>#include<cmath>using namespace std;__int64 mm,nn,xx,yy,l;__int64 c,d,x,y;__int64 modd(__int64 a, __int64 b){if(a>=0)return a%b;elsereturn a%b+b;}__int64 exGcd(__int64 a, __int64 b) {if(b==0){x=1;y=0;return a;}__int64 r=exGcd(b, a%b);__int64 t=x;x=y;y=t-a/b*y;return r;}int main(){scanf("%I64d %I64d %I64d %I64d %I64d",&xx,&yy,&mm,&nn,&l);if(mm>nn) //分情况{d=exGcd(mm-nn,l);c=yy-xx;}else{d=exGcd(nn-mm,l);c=xx-yy;}if(c%d != 0){printf("Impossible\n");return 0;}l=l/d;x=modd(x*c/d,l); ///取模函数要注意printf("%I64d\n",x);system("pause");return 0;}POJ 1142 SmithNumber题意:寻找最接近而且大于给定的数字的SmithNumber什么是SmithNumber?用sum(int)表示一个int的各位的和,那一个数i如果是SmithNumber,则sum(i) =sigma( sum(Pj )),Pj表示i的第j个质因数。
ACM算法模板(吉林大学)

目录目录 (1)Graph 图论 (3)|DAG的深度优先搜索标记 (3)|无向图找桥 (3)|无向图连通度(割) (3)|最大团问题DP+DFS (3)|欧拉路径O(E) (3)|D IJKSTRA数组实现O(N^2) (3)|D IJKSTRA O(E* LOG E) (4)|B ELLMAN F ORD单源最短路O(VE) (4)|SPFA(S HORTEST P ATH F ASTER A LGORITHM) (4)|第K短路(D IJKSTRA) (5)|第K短路(A*) (5)|P RIM求MST (6)|次小生成树O(V^2) (6)|最小生成森林问题(K颗树)O(MLOGM) (6)|有向图最小树形图 (6)|M INIMAL S TEINER T REE (6)|T ARJAN强连通分量 (7)|弦图判断 (7)|弦图的PERFECT ELIMINATION点排列 (7)|稳定婚姻问题O(N^2) (7)|拓扑排序 (8)|无向图连通分支(DFS/BFS邻接阵) (8)|有向图强连通分支(DFS/BFS邻接阵)O(N^2) (8)|有向图最小点基(邻接阵)O(N^2) (9)|F LOYD求最小环 (9)|2-SAT问题 (9)Network 网络流 (11)|二分图匹配(匈牙利算法DFS实现) (11)|二分图匹配(匈牙利算法BFS实现) (11)|二分图匹配(H OPCROFT-C ARP的算法) (11)|二分图最佳匹配(KUHN MUNKRAS算法O(M*M*N))..11 |无向图最小割O(N^3) (12)|有上下界的最小(最大)流 (12)|D INIC最大流O(V^2*E) (12)|HLPP最大流O(V^3) (13)|最小费用流O(V*E* F).......................................13|最小费用流O(V^2* F). (14)|最佳边割集 (15)|最佳点割集 (15)|最小边割集 (15)|最小点割集(点连通度) (16)|最小路径覆盖O(N^3) (16)|最小点集覆盖 (16)Structure 数据结构 (17)|求某天是星期几 (17)|左偏树合并复杂度O(LOG N) (17)|树状数组 (17)|二维树状数组 (17)|T RIE树(K叉) (17)|T RIE树(左儿子又兄弟) (18)|后缀数组O(N* LOG N) (18)|后缀数组O(N) (18)|RMQ离线算法O(N*LOG N)+O(1) (19)|RMQ(R ANGE M INIMUM/M AXIMUM Q UERY)-ST算法(O(NLOGN +Q)) (19)|RMQ离线算法O(N*LOG N)+O(1)求解LCA (19)|LCA离线算法O(E)+O(1) (20)|带权值的并查集 (20)|快速排序 (20)|2台机器工作调度 (20)|比较高效的大数 (20)|普通的大数运算 (21)|最长公共递增子序列O(N^2) (22)|0-1分数规划 (22)|最长有序子序列(递增/递减/非递增/非递减) (22)|最长公共子序列 (23)|最少找硬币问题(贪心策略-深搜实现) (23)|棋盘分割 (23)|汉诺塔 (23)|STL中的PRIORITY_QUEUE (24)|堆栈 (24)|区间最大频率 (24)|取第K个元素 (25)|归并排序求逆序数 (25)|逆序数推排列数 (25)|二分查找 (25)|二分查找(大于等于V的第一个值) (25)|所有数位相加 (25)Number 数论 (26)|递推求欧拉函数PHI(I) (26)|单独求欧拉函数PHI(X) (26)|GCD最大公约数 (26)|快速GCD (26)|扩展GCD (26)|模线性方程 A * X = B (% N) (26)|模线性方程组 (26)|筛素数[1..N] (26)|高效求小范围素数[1..N] (26)|随机素数测试(伪素数原理) (26)|组合数学相关 (26)|P OLYA计数 (27)|组合数C(N, R) (27)|最大1矩阵 (27)|约瑟夫环问题(数学方法) (27)|约瑟夫环问题(数组模拟) (27)|取石子游戏1 (27)|集合划分问题 (27)|大数平方根(字符串数组表示) (28)|大数取模的二进制方法 (28)|线性方程组A[][]X[]=B[] (28)|追赶法解周期性方程 (28)|阶乘最后非零位,复杂度O(NLOGN) (29)递归方法求解排列组合问题 (30)|类循环排列 (30)|全排列 (30)|不重复排列 (30)|全组合 (31)|不重复组合 (31)|应用 (31)模式串匹配问题总结 (32)|字符串H ASH (32)|KMP匹配算法O(M+N) (32)|K ARP-R ABIN字符串匹配 (32)|基于K ARP-R ABIN的字符块匹配 (32)|函数名: STRSTR (32)|BM算法的改进的算法S UNDAY A LGORITHM (32)|最短公共祖先(两个长字符串) (33)|最短公共祖先(多个短字符串)...............................33Geometry 计算几何.. (34)|G RAHAM求凸包O(N* LOG N) (34)|判断线段相交 (34)|求多边形重心 (34)|三角形几个重要的点 (34)|平面最近点对O(N* LOG N) (34)|L IUCTIC的计算几何库 (35)|求平面上两点之间的距离 (35)|(P1-P0)*(P2-P0)的叉积 (35)|确定两条线段是否相交 (35)|判断点P是否在线段L上 (35)|判断两个点是否相等 (35)|线段相交判断函数 (35)|判断点Q是否在多边形内 (35)|计算多边形的面积 (35)|解二次方程A X^2+B X+C=0 (36)|计算直线的一般式A X+B Y+C=0 (36)|点到直线距离 (36)|直线与圆的交点,已知直线与圆相交 (36)|点是否在射线的正向 (36)|射线与圆的第一个交点 (36)|求点P1关于直线LN的对称点P2 (36)|两直线夹角(弧度) (36)ACM/ICPC竞赛之STL (37)ACM/ICPC竞赛之STL简介 (37)ACM/ICPC竞赛之STL--PAIR (37)ACM/ICPC竞赛之STL--VECTOR (37)ACM/ICPC竞赛之STL--ITERATOR简介 (38)ACM/ICPC竞赛之STL--STRING (38)ACM/ICPC竞赛之STL--STACK/QUEUE (38)ACM/ICPC竞赛之STL--MAP (40)ACM/ICPC竞赛之STL--ALGORITHM (40)STL IN ACM (41)头文件 (42)线段树 (43)求矩形并的面积(线段树+离散化+扫描线) (43)求矩形并的周长(线段树+离散化+扫描线) (44)Graph 图论/*==================================================*\| DAG的深度优先搜索标记| INIT: edge[][]邻接矩阵; pre[], post[], tag全置0;| CALL: dfstag(i, n); pre/post:开始/结束时间\*==================================================*/int edge[V][V], pre[V], post[V], tag;void dfstag(int cur, int n){ // vertex: 0 ~ n-1pre[cur] = ++tag;for (int i=0; i<n; ++i) if (edge[cur][i]) {if (0 == pre[i]) {printf("Tree Edge!\n");dfstag(i,n);} else {if (0 == post[i]) printf("Back Edge!\n");else if (pre[i] > pre[cur])printf("Down Edge!\n");else printf("Cross Edge!\n");}}post[cur] = ++tag;}/*==================================================*\| 无向图找桥| INIT: edge[][]邻接矩阵;vis[],pre[],anc[],bridge 置0;| CALL: dfs(0, -1, 1, n);\*==================================================*/int bridge, edge[V][V], anc[V], pre[V], vis[V];void dfs(int cur, int father, int dep, int n){ // vertex: 0 ~ n-1if (bridge) return;vis[cur] = 1; pre[cur] = anc[cur] = dep;for (int i=0; i<n; ++i) if (edge[cur][i]) {if (i != father && 1 == vis[i]) {if (pre[i] < anc[cur])anc[cur] = pre[i];//back edge}if (0 == vis[i]) { //tree edgedfs(i,cur,dep+1,n);if (bridge) return;if (anc[i] < anc[cur]) anc[cur] = anc[i];if (anc[i] > pre[cur]) { bridge = 1; return; } }}vis[cur] = 2;}/*==================================================*\| 无向图连通度(割)| INIT: edge[][]邻接矩阵;vis[],pre[],anc[],deg[]置为0;| CALL: dfs(0, -1, 1, n);| k=deg[0], deg[i]+1(i=1…n-1)为删除该节点后得到的连通图个数| 注意:0作为根比较特殊!\*==================================================*/int edge[V][V], anc[V], pre[V], vis[V], deg[V];void dfs(int cur, int father, int dep, int n){// vertex: 0 ~ n-1int cnt = 0;vis[cur] = 1; pre[cur] = anc[cur] = dep;for (int i=0; i<n; ++i) if (edge[cur][i]) {if (i != father && 1 == vis[i]) {if (pre[i] < anc[cur])anc[cur] = pre[i];//back edge}if (0 == vis[i]) { //tree edgedfs(i,cur,dep+1,n);++cnt; // 分支个数if (anc[i] < anc[cur]) anc[cur] = anc[i];if ((cur==0 && cnt>1) ||(cnt!=0 && anc[i]>=pre[cur]))++deg[cur];// link degree of a vertex }}vis[cur] = 2;} /*==================================================*\| 最大团问题 DP + DFS| INIT: g[][]邻接矩阵;| CALL: res = clique(n);\*==================================================*/int g[V][V], dp[V], stk[V][V], mx;int dfs(int n, int ns, int dep){if (0 == ns) {if (dep > mx) mx = dep;return 1;}int i, j, k, p, cnt;for (i = 0; i < ns; i++) {k = stk[dep][i]; cnt = 0;if (dep + n - k <= mx) return 0;if (dep + dp[k] <= mx) return 0;for (j = i + 1; j < ns; j++) {p=stk[dep][j];if (g[k][p]) stk[dep + 1][cnt++] = p;}dfs(n, cnt, dep + 1);}return 1;}int clique(int n){int i, j, ns;for (mx = 0, i = n - 1; i >= 0; i--) {// vertex: 0 ~ n-1for (ns = 0, j = i + 1; j < n; j++)if (g[i][j]) stk[1][ ns++ ] = j;dfs(n, ns, 1); dp[i] = mx;}return mx;}/*==================================================*\| 欧拉路径O(E)| INIT: adj[][]置为图的邻接表; cnt[a]为a点的邻接点个数;| CALL: elpath(0); 注意:不要有自向边\*==================================================*/int adj[V][V], idx[V][V], cnt[V], stk[V], top;int path(int v){for (int w ; cnt[v] > 0; v = w) {stk[ top++ ] = v;w = adj[v][ --cnt[v] ];adj[w][ idx[w][v] ] = adj[w][ --cnt[w] ];// 处理的是无向图—-边是双向的,删除v->w后,还要处理删除w->v}return v;}void elpath (int b, int n){ // begin from b int i, j;for (i = 0; i < n; ++i) // vertex: 0 ~ n-1 for (j = 0; j < cnt[i]; ++j)idx[i][ adj[i][j] ] = j;printf("%d", b);for (top = 0; path(b) == b && top != 0; ) {b = stk[ --top ];printf("-%d", b);}printf("\n");}/*==================================================*\| Dijkstra数组实现O(N^2)| Dijkstra --- 数组实现(在此基础上可直接改为STL的Queue实现)| lowcost[] --- beg到其他点的最近距离| path[] -- beg为根展开的树,记录父亲结点\*==================================================*/#define INF 0x03F3F3F3Fconst int N;int path[N], vis[N];void Dijkstra(int cost[][N], int lowcost[N], int n, int beg){ int i, j, min;memset(vis, 0, sizeof(vis));vis[beg] = 1;for (i=0; i<n; i++){lowcost[i] = cost[beg][i]; path[i] = beg;}lowcost[beg] = 0;path[beg] = -1; // 树根的标记int pre = beg;for (i=1; i<n; i++){min = INF;dist[v] = dist[u] + c;for (j=0; j<n; j++)// 下面的加法可能导致溢出,INF 不能取太大if (vis[j]==0 &&lowcost[pre]+cost[pre][j]<lowcost[j]){lowcost[j] =lowcost[pre] + cost[pre][j]; path[j] = pre; } for (j=0; j<n; j++) if (vis[j] == 0 && lowcost[j] < min){ min = lowcost[j]; pre = j; } vis[pre] = 1; } } /*==================================================*\ | Dijkstra O(E * log E) | INIT: 调用init(nv, ne)读入边并初始化; | CALL: dijkstra(n, src); dist[i]为src 到i 的最短距离 \*==================================================*/ #define typec int // type of cost const typec inf = 0x3f3f3f3f; // max of cost typec cost[E], dist[V]; int e, pnt[E], nxt[E], head[V], prev[V], vis[V]; struct qnode { int v; typec c; qnode (int vv = 0, typec cc = 0) : v(vv), c(cc) {} bool operator < (const qnode& r) const { return c>r.c; } }; void dijkstra(int n, const int src){ qnode mv; int i, j, k, pre; priority_queue<qnode> que; vis[src] = 1; dist[src] = 0; que.push(qnode(src, 0)); for (pre = src, i=1; i<n; i++) { for (j = head[pre]; j != -1; j = nxt[j]) { k = pnt[j]; if (vis[k] == 0 && dist[pre] + cost[j] < dist[k]){ dist[k] =dist[pre] + cost[j]; que.push(qnode(pnt[j], dist[k])); prev[k] = pre; } } while (!que.empty() && vis[que.top().v] == 1) que.pop(); if (que.empty()) break ; mv = que.top(); que.pop(); vis[pre = mv.v] = 1; } } inline void addedge(int u, int v, typec c){ pnt[e] = v; cost[e] = c; nxt[e] = head[u]; head[u] = e++; } void init(int nv, int ne){ int i, u, v; typec c; e = 0;memset(head, -1, sizeof (head));memset(vis, 0, sizeof (vis));memset(prev, -1, sizeof (prev));for (i = 0; i < nv; i++) dist[i] = inf;for (i = 0; i < ne; ++i) {scanf("%d%d%d", &u, &v, &c);// %d: type of cost addedge(u, v, c); // vertex: 0 ~ n-1, 单向边 }}/*==================================================*\| BellmanFord 单源最短路O(VE)| 能在一般情况下,包括存在负权边的情况下,解决单源最短路径问题| INIT: edge[E][3]为边表| CALL: bellman(src);有负环返回0;dist[i]为src 到i 的最短距| 可以解决差分约束系统: 需要首先构造约束图,构造不等式时>=表示求最小值, 作为最长路,<=表示求最大值, 作为最短路 (v-u <= c:a[u][v] = c )\*==================================================*/#define typec int // type of costconst typec inf=0x3f3f3f3f; // max of costint n, m, pre[V], edge[E][3];typec dist[V];int relax (int u, int v, typec c){if (dist[v] > dist[u] + c) {pre[v] = u; return 1; } return 0; } int bellman (int src){ int i, j;for (i=0; i<n; ++i) { dist[i] = inf; pre[i] = -1; } dist[src] = 0; bool flag; for (i=1; i<n; ++i){ flag = false; // 优化 for (j=0; j<m; ++j) { if( 1 == relax(edge[j][0], edge[j][1], edge[j][2]) ) flag = true; } if( !flag ) break; } for (j=0; j<m; ++j) { if (1 == relax(edge[j][0], edge[j][1], edge[j][2])) return 0; // 有负圈 } return 1; } /*==================================================*\ | SPFA(Shortest Path Faster Algorithm) Bellman-Ford 算法的一种队列实现,减少了不必要的冗余计算。
atcoder abc 欧拉函数

atcoder abc 欧拉函数欧拉函数是数论中的一个重要概念,与素数、数论函数等密切相关。
在atcoder竞赛中,经常会遇到涉及欧拉函数的题目。
本文将详细介绍欧拉函数的定义、性质及应用,并结合atcoder的题目展示欧拉函数的实际应用。
一、欧拉函数的定义1.1 欧拉函数的概念欧拉函数又称欧拉ϕ函数,表示小于或等于n的正整数中与n互质的数的个数。
用符号表示为ϕ(n)。
1.2 欧拉函数的计算公式计算欧拉函数的方法一般有两种:(1)质因数分解法:将n进行质因数分解,得到n=p₁^a₁ * p₂^a₂ * … * pₖ^aₖ,其中p₁,p₂,…,pₖ为n的质因数,a₁,a₂,…,aₖ为对应的幂次。
则有ϕ(n) = n * (1-1/p₁) * (1-1/p₂) * … * (1-1/pₖ)(2)递推公式法:ϕ(n) = n * (1-1/p₁) * (1-1/p₂) * … * (1-1/pₖ),其中p₁,p₂,…,pₖ为n 的不同质因数。
1.3 欧拉函数的性质根据欧拉函数的定义和计算公式,可以得到以下性质:(1)若n为素数,则ϕ(n) = n-1。
(2)若n为正整数m的倍数,则ϕ(n) = n * (1-1/p₁) * (1-1/p₂) * … * (1-1/pₖ),其中p₁,p₂,…,pₖ为n的不同质因数。
(3)若a和b互质,则ϕ(a*b)=ϕ(a)*ϕ(b)。
二、欧拉函数的应用2.1 欧拉定理欧拉定理是欧拉函数的一个重要应用,它表明:若a与m互质,则a^ϕ(m) ≡ 1 (mod m)。
2.2 欧拉降幂欧拉降幂是利用欧拉函数的性质,求解大数次方的一种常用方法。
其公式为:a^b mod m = a^(b mod ϕ(m) + ϕ(m)) mod m。
2.3 欧拉函数在atcoder竞赛中的应用在atcoder竞赛中,经常会出现涉及欧拉函数的题目。
给定n个数,求满足条件的数对的个数,其中条件为这对数的最大公约数等于1。
ACM中的数学问题March总结

欧几里德算法
• 欧几里德算法 (The Euclidean Algorithm) • 又称辗转相除法 或者 短除法 • 原理: gcd(a,b) = gcd(b,a mod b) • 证明: • 利用整除性质5(a=kb±c => a,b的公因数与b,c的公因数完全相同) • 辗转相除直到两数整除,其中的除数就是要求的最大公约数。
第16页/共96页
请写出12,10共有的倍 数
第17页/共96页
请写出12,10共有的倍 数
60,
第18页/共96页
请写出12,10共有的倍 数
60, 120,
第19页/共96页
请写出12,10共有的倍 数
60, 120, 180,
第20页/共96页
请写出12,10共有的倍 数
60, 120, 180, 240…
第7页/共96页
整除的基本性质
• 性质1: • a|b,b|c => a|c
• 性质2 : • a|b => a|bc
• 性质3 : • a|b,a|c => a|kb±lc
• 性质4 : • a|b,b|a => a=±b
第8页/共96页
整除的基本性质
• 性质5 : • a=kb±c => a,b的公因数与b,c的公因数完全相同 • 证明: • 假设d是b,c的公因数,即d|b, d|c。 • 利用整除性质3,d整除b,c的线性组合,故d|a。 • 所以d是a,b的公因数 • 反之,如果d是a,b的公因数,也能证出d是b,c的公因数
第34页/共96页
扩展欧几里德算法
• 扩展欧几里德算法(递归实现):
第35页/共96页
扩展欧几里德算法
-【精品资料】ACM大赛必备_常用函数整理_ACM模板(整理版)

目录一、数学问题 (4)1.精度计算——大数阶乘 (4)2.精度计算——乘法(大数乘小数) (4)3.精度计算——乘法(大数乘大数) (5)4.精度计算——加法 (6)5.精度计算——减法 (7)6.任意进制转换 (8)7.最大公约数、最小公倍数 (9)8.组合序列 (10)9.快速傅立叶变换(FFT) (10)10.Ronberg 算法计算积分 (12)11.行列式计算 (14)12.求排列组合数 (15)13.求某一天星期几 (15)14.卡特兰(Catalan) 数列原理 (16)15.杨辉三角 (16)16.全排列 (17)17.匈牙利算法----最大匹配问题 (18)18.最佳匹配KM 算法 (20)二、字符串处理 (22)1.字符串替换 (22)2.字符串查找 (23)3.字符串截取 (24)4.LCS-最大公共子串长度 (24)5.LCS-最大公共子串长度 (25)6.数字转换为字符 (26)三、计算几何 (27)1.叉乘法求任意多边形面积 (27)2.求三角形面积 (27)3.两矢量间角度 (28)4.两点距离(2D、3D) (28)5.射向法判断点是否在多边形内部 (29)6.判断点是否在线段上 (30)7.判断两线段是否相交 (31)8.判断线段与直线是否相交 (32)9.点到线段最短距离 (32)10.求两直线的交点 (33)11.判断一个封闭图形是凹集还是凸集 (34)12.Graham 扫描法寻找凸包 (35)13.求两条线段的交点 (36)四、数论 (37)1.x 的二进制长度 (37)2.返回x 的二进制表示中从低到高的第i 位 (38)3.模取幂运算 (38)4.求解模线性方程 (39)5.求解模线性方程组(中国余数定理) (39)6.筛法素数产生器 (40)7.判断一个数是否素数 (41)8.求距阵最大和 (42)8.求一个数每一位相加之和 (43)10.质因数分解 (43)11.高斯消元法解线性方程组 (44)五、图论 (45)1.Prim 算法求最小生成树................................................. 45 2.Dijkstra 算法求单源最短路径.. (46)3.Bellman-ford 算法求单源最短路径 (47)4.Floyd-Warshall 算法求每对节点间最短路径 (48)5.解欧拉图 (49)六、排序/查找 (50)1.快速排序 (50)2.希尔排序 (51)3.选择法排序 (52)4.二分查找 (52)七、数据结构 (53)1.顺序队列 (53)2.顺序栈 (56)3.链表 (59)4.链栈 (63)5.二叉树 (66)八、高精度运算专题 (68)1.专题函数说明 (68)2.高精度数比较 (69)3.高精度数加法 (69)4.高精度数减法 (70)5.高精度乘10 (71)6.高精度乘单精度 (71)7.高精度乘高精度 (72)8.高精度除单精度 (72)9.高精度除高精度 (73)九、标准模板库的使用 (74)1.计算求和 (74)2.求数组中的最大值 (76)3. sort 和qsort (76)十、其他 (78)1.运行时间计算 (78)DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD一、数学问题1.精度计算——大数阶乘语法:int result=factorial(int n);参数:n:n 的阶乘返回值:阶乘结果的位数注意:本程序直接输出n!的结果,需要返回结果请保留long a[] 需要math.h源程序:int factorial(int n){long a[10000];int i,j,l,c,m=0,w;a[0]=1;for(i=1;i<=n;i++){c=0;for(j=0;j<=m;j++){a[j]=a[j]*i+c;c=a[j]/10000;a[j]=a[j]%10000;}if(c>0) {m++;a[m]=c;}}w=m*4+log10(a[m])+1;printf("\n%ld",a[m]);for(i=m-1;i>=0;i--) printf("%4.4ld",a[i]);return w;}我也可以做到..5 / 782.精度计算——乘法(大数乘小数)语法:mult(char c[],char t[],int m);参数:c[]:被乘数,用字符串表示,位数不限t[]:结果,用字符串表示m:乘数,限定10 以内返回值:null注意:需要string.h源程序:void mult(char c[],char t[],int m){int i,l,k,flag,add=0;char s[100];l=strlen(c);for (i=0;i<l;i++)s[l-i-1]=c[i]-'0';for (i=0;i<l;i++){k=s[i]*m+add;if (k>=10) {s[i]=k%10;add=k/10;flag=1;} else{s[i]=k;flag=0;add=0;}}if (flag) {l=i+1;s[i]=add;} else l=i;for (i=0;i<l;i++)t[l-1-i]=s[i]+'0'; t[l]='\0';}3.精度计算——乘法(大数乘大数)语法:mult(char a[],char b[],char s[]);参数:a[]:被乘数,用字符串表示,位数不限b[]:乘数,用字符串表示,位数不限t[]:结果,用字符串表示返回值:null注意:空间复杂度为o(n^2)需要string.h源程序:void mult(char a[],char b[],char s[]){我也可以做到..6 / 78int i,j,k=0,alen,blen,sum=0,res[65][65]={0},flag=0; char result[65];alen=strlen(a);blen=strlen(b);for (i=0;i<alen;i++)for (j=0;j<blen;j++) res[i][j]=(a[i]-'0')*(b[j]-'0');for (i=alen-1;i>=0;i--){for (j=blen-1;j>=0;j--) sum=sum+res[i+blen-j-1][j]; result[k]=sum%10;k=k+1;sum=sum/10;}for (i=blen-2;i>=0;i--){for (j=0;j<=i;j++) sum=sum+res[i-j][j];result[k]=sum%10;k=k+1;sum=sum/10;}if (sum!=0) {result[k]=sum;k=k+1;}for (i=0;i<k;i++) result[i]+='0';for (i=k-1;i>=0;i--) s[i]=result[k-1-i];s[k]='\0';while(1){if (strlen(s)!=strlen(a)&&s[0]=='0')strcpy(s,s+1);elsebreak;}}4.精度计算——加法语法:add(char a[],char b[],char s[]);参数:a[]:被加数,用字符串表示,位数不限b[]:加数,用字符串表示,位数不限s[]:结果,用字符串表示返回值:null注意:空间复杂度为o(n^2)我也可以做到..7 / 78需要string.hDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD源程序:void add(char a[],char b[],char back[]){int i,j,k,up,x,y,z,l;char *c;if (strlen(a)>strlen(b)) l=strlen(a)+2; else l=strlen(b)+2; c=(char *) malloc(l*sizeof(char));i=strlen(a)-1;j=strlen(b)-1;k=0;up=0;while(i>=0||j>=0){if(i<0) x='0'; else x=a[i];if(j<0) y='0'; else y=b[j];z=x-'0'+y-'0';if(up) z+=1;if(z>9) {up=1;z%=10;} else up=0;c[k++]=z+'0';i--;j--;}if(up) c[k++]='1';i=0;c[k]='\0';for(k-=1;k>=0;k--)back[i++]=c[k];back[i]='\0';}5.精度计算——减法语法:sub(char s1[],char s2[],char t[]);参数:s1[]:被减数,用字符串表示,位数不限s2[]:减数,用字符串表示,位数不限t[]:结果,用字符串表示返回值:null注意:默认s1>=s2,程序未处理负数情况需要string.h源程序:void sub(char s1[],char s2[],char t[])我也可以做到..8 / 78{int i,l2,l1,k;l2=strlen(s2);l1=strlen(s1);t[l1]='\0';l1--;for (i=l2-1;i>=0;i--,l1--){if (s1[l1]-s2[i]>=0)t[l1]=s1[l1]-s2[i]+'0';else{t[l1]=10+s1[l1]-s2[i]+'0';s1[l1-1]=s1[l1-1]-1;}}k=l1;while(s1[k]<0) {s1[k]+=10;s1[k-1]-=1;k--;}while(l1>=0) {t[l1]=s1[l1];l1--;}loop:if (t[0]=='0') {l1=strlen(s1);for (i=0;i<l1-1;i++) t[i]=t[i+1];t[l1-1]='\0';goto loop;}if (strlen(t)==0) {t[0]='0';t[1]='\0';}}6.任意进制转换语法:conversion(char s1[],char s2[],char t[]);参数:s[]:转换前的数字s2[]:转换后的数字d1:原进制数d2:需要转换到的进制数返回值:null注意:高于9 的位数用大写'A'~'Z'表示,2~16 位进制通过验证源程序:void conversion(char s[],char s2[],long d1,long d2){我也可以做到..9 / 78long i,j,t,num;char c;num=0;for (i=0;s[i]!='\0';i++){if (s[i]<='9'&&s[i]>='0') t=s[i]-'0'; else t=s[i]-'A'+10;num=num*d1+t;}i=0;while(1){t=num%d2;if (t<=9) s2[i]=t+'0'; else s2[i]=t+'A'-10;num/=d2;if (num==0) break;i++;}for (j=0;j<i/2;j++){c=s2[j];s2[j]=s[i-j];s2[i-j]=c;}s2[i+1]='\0';}7.最大公约数、最小公倍数语法:resulet=hcf(int a,int b)、result=lcd(int a,int b)参数:a:int a,求最大公约数或最小公倍数b:int b,求最大公约数或最小公倍数返回值:返回最大公约数(hcf)或最小公倍数(lcd)注意:lcd 需要连同hcf 使用源程序:int hcf(int a,int b){int r=0;while(b!=0){r=a%b;a=b;DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDb=r;}return(a);我也可以做到..10 / 78}lcd(int u,int v,int h){return(u*v/h);}8.组合序列语法:m_of_n(int m, int n1, int m1, int* a, int head)参数:m:组合数C 的上参数n1:组合数C 的下参数m1:组合数C 的上参数,递归之用*a:1~n 的整数序列数组head:头指针返回值:null注意:*a 需要自行产生初始调用时,m=m1、head=0调用例子:求C(m,n)序列:m_of_n(m,n,m,a,0);源程序:void m_of_n(int m, int n1, int m1, int* a, int head){int i,t;if(m1<0 || m1>n1) return;if(m1==n1){return;}m_of_n(m,n1-1,m1,a,head); // 递归调用t=a[head];a[head]=a[n1-1+head];a[n1-1+head]=t;m_of_n(m,n1-1,m1-1,a,head+1); // 再次递归调用t=a[head];a[head]=a[n1-1+head];a[n1-1+head]=t;}9.快速傅立叶变换(FFT)语法:kkfft(double pr[],double pi[],int n,int k,double fr[],double fi[],intl,int il);参数:我也可以做到..11 / 78pr[n]:输入的实部pi[n]:数入的虚部n,k:满足n=2^kfr[n]:输出的实部fi[n]:输出的虚部l:逻辑开关,0 FFT,1 ifFTil:逻辑开关,0 输出按实部/虚部;1 输出按模/幅角返回值:null注意:需要math.h源程序:void kkfft(pr,pi,n,k,fr,fi,l,il)int n,k,l,il;double pr[],pi[],fr[],fi[];{int it,m,is,i,j,nv,l0; double p,q,s,vr,vi,poddr,poddi;for (it=0; it<=n-1; it++){m=it; is=0;for (i=0; i<=k-1; i++){j=m/2; is=2*is+(m-2*j); m=j;}fr[it]=pr[is]; fi[it]=pi[is];}pr[0]=1.0; pi[0]=0.0;p=6.283185306/(1.0*n);pr[1]=cos(p); pi[1]=-sin(p);if (l!=0) pi[1]=-pi[1];for (i=2; i<=n-1; i++){p=pr[i-1]*pr[1];q=pi[i-1]*pi[1];s=(pr[i-1]+pi[i-1])*(pr[1]+pi[1]);pr[i]=p-q; pi[i]=s-p-q;}for (it=0; it<=n-2; it=it+2){vr=fr[it]; vi=fi[it];fr[it]=vr+fr[it+1]; fi[it]=vi+fi[it+1];fr[it+1]=vr-fr[it+1]; fi[it+1]=vi-fi[it+1]; }m=n/2; nv=2;for (l0=k-2; l0>=0; l0--){我也可以做到..12 / 78m=m/2; nv=2*nv;for (it=0; it<=(m-1)*nv; it=it+nv)for (j=0; j<=(nv/2)-1; j++){p=pr[m*j]*fr[it+j+nv/2];q=pi[m*j]*fi[it+j+nv/2];s=pr[m*j]+pi[m*j];s=s*(fr[it+j+nv/2]+fi[it+j+nv/2]); poddr=p-q; poddi=s-p-q;fr[it+j+nv/2]=fr[it+j]-poddr;fi[it+j+nv/2]=fi[it+j]-poddi;fr[it+j]=fr[it+j]+poddr;fi[it+j]=fi[it+j]+poddi;}}if (l!=0)for (i=0; i<=n-1; i++){fr[i]=fr[i]/(1.0*n);fi[i]=fi[i]/(1.0*n);}if (il!=0)for (i=0; i<=n-1; i++){pr[i]=sqrt(fr[i]*fr[i]+fi[i]*fi[i]);if (fabs(fr[i])<0.000001*fabs(fi[i])) {if ((fi[i]*fr[i])>0) pi[i]=90.0;else pi[i]=-90.0;}DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDelsepi[i]=atan(fi[i]/fr[i])*360.0/6.283185306;}return;}10.Ronberg 算法计算积分语法:result=integral(double a,double b);参数:a:积分上限b:积分下限我也可以做到..13 / 78function f:积分函数返回值:f 在(a,b)之间的积分值注意:function f(x)需要自行修改,程序中用的是sina(x)/x 需要math.h默认精度要求是1e-5源程序:double f(double x){return sin(x)/x; //在这里插入被积函数}double integral(double a,double b){double h=b-a;double t1=(1+f(b))*h/2.0;int k=1;double r1,r2,s1,s2,c1,c2,t2;loop:double s=0.0;double x=a+h/2.0;while(x<b){s+=f(x);x+=h;}t2=(t1+h*s)/2.0;s2=t2+(t2-t1)/3.0;if(k==1){k++;h/=2.0;t1=t2;s1=s2;goto loop;}c2=s2+(s2-s1)/15.0;if(k==2){c1=c2;k++;h/=2.0;t1=t2;s1=s2;goto loop;}r2=c2+(c2-c1)/63.0;if(k==3){r1=r2; c1=c2;k++;h/=2.0;t1=t2;s1=s2;我也可以做到..14 / 78goto loop;}while(fabs(1-r1/r2)>1e-5){ r1=r2;c1=c2;k++;h/=2.0;t1=t2;s1=s2;goto loop;}return r2;}11.行列式计算语法:result=js(int s[][],int n)参数:s[][]:行列式存储数组n:行列式维数,递归用返回值:行列式值注意:函数中常数N 为行列式维度,需自行定义源程序:int js(s,n)int s[][N],n;{int z,j,k,r,total=0;int b[N][N];/*b[N][N]用于存放,在矩阵s[N][N]中元素s[0]的余子式*/if(n>2){for(z=0;z<n;z++){for(j=0;j<n-1;j++)for(k=0;k<n-1;k++)if(k>=z) b[j][k]=s[j+1][k+1]; elseb[j][k]=s[j+1][k];if(z%2==0) r=s[0][z]*js(b,n-1); /*递归调用*/else r=(-1)*s[0][z]*js(b,n-1);total=total+r;}}else if(n==2)total=s[0][0]*s[1][1]-s[0][1]*s[1][0];return total;我也可以做到..15 / 78}12.求排列组合数语法:result=P(long n,long m); / result=long C(long n,long m);参数:m:排列组合的上系数n:排列组合的下系数返回值:排列组合数注意:符合数学规则:m<=n源程序:long P(long n,long m){long p=1;while(m!=0){p*=n;n--;m--;}return p;}long C(long n,long m){long i,c=1;DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDi=m;while(i!=0){c*=n;n--;i--;}while(m!=0){c/=m;m--;}return c;}13.求某一天星期几语法:result=weekday(int N,int M,int d)参数:N,M,d:年月日,例如:2003,11,4返回值:0:星期天,1 星期一……注意:需要math.h适用于1582 年10 月15 日之后, 因为罗马教皇格里高利十三世在这一天启用新历法.源程序:我也可以做到..16 / 78int weekday(int N,int M,int d){int m,n,c,y,w;m=(M-2)%12;if (M>=3) n=N;else n=N-1;c=n/100;y=n%100;w=(int)(d+floor(13*m/5)+y+floor(y/4)+floor(c/4)-2*c)%7;while(w<0) w+=7;return w;}14.卡特兰(Catalan) 数列原理令h(1)=1,catalan 数满足递归式:h(n)= h(1)*h(n-1) + h(2)*h(n-2) + ... + h(n-1)h(1) (其中n>=2)该递推关系的解为:h(n)=c(2n-2,n-1)/n (n=1,2,3,...)1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440,9694845, 35357670, 129644790, 477638700, 1767263190, 6564120420,24466267020, 91482563640, 343059613650, 1289904147324, 4861946401452, …1.括号化问题。
ACM-数论

a b m (mod ) d d d
公约数、公倍数及互素
定义: 公约数,亦称“公因数”。如果一个整数同时是几个整数的 约数,称这个整数为它们的“公约数”;公约数中最大的 称为最大公约数(Greatest Common Divisor 缩写G.C.D )。
性质4 设p为素数且p|ab,则p|a或p|b 定理2(唯一分解定理)任一自然数n皆可唯一表为素数之 积
ak a1 a2 n p1 p2 ... pk
p1 p2 ... pk 为素数,a1 , a2 ,
, ak 为自然数
几个数论函数
函数[x]
设x是实数,不大于x的最大整数称为x的整数部分,记为[x];x-[x] 称为x的小数部分,记为{x}。 性质:若p a || n !,则a [ n ] [ n2 ] [ n3 ] ...
又35 243 250-7 -7(mod 50),于是
26 5 2 (25733 +46) (35) 3 (-7)5 3 (72) 7 3 21 29(mod 50)
注意到0 29 50,所以29就是所求余数
事实上,a k 1(mod m)时, 对于大的指数n,利用带余除法定理,可得n=kq+r, 0 r k,于是有 a n a kq r (a k ) q a r a r (mod m)
应用
性质1给出了一种将整除关系转变为同余式的法则
a ≡b(mod m) ←→ a-b ≡0(mod m) ←→ m | a-b
ACM经典的题目代码

目录一.数论 41.阶乘最后非零位 42. 模线性方程(组) 43. 素数表64. 素数随机判定(miller_rabin) 65. 质因数分解76. 最大公约数欧拉函数8二.图论_匹配91. 二分图最大匹配(hungary邻接表形式) 92. 二分图最大匹配(hungary邻接表形式,邻接阵接口) 103. 二分图最大匹配(hungary邻接阵形式) 104. 二分图最大匹配(hungary正向表形式) 115. 二分图最佳匹配(kuhn_munkras邻接阵形式) 116. 一般图匹配(邻接表形式) 127. 一般图匹配(邻接表形式,邻接阵接口) 138. 一般图匹配(邻接阵形式) 149. 一般图匹配(正向表形式) 15三.图论_生成树161. 最小生成树(kruskal邻接表形式) 162. 最小生成树(kruskal正向表形式) 173. 最小生成树(prim+binary_heap邻接表形式) 194. 最小生成树(prim+binary_heap正向表形式) 205. 最小生成树(prim+mapped_heap邻接表形式) 216. 最小生成树(prim+mapped_heap正向表形式) 227. 最小生成树(prim邻接阵形式) 238. 最小树形图(邻接阵形式) 24四.图论_网络流251. 上下界最大流(邻接表形式) 252. 上下界最大流(邻接阵形式) 263. 上下界最小流(邻接表形式) 274. 上下界最小流(邻接阵形式) 295. 最大流(邻接表形式) 306. 最大流(邻接表形式,邻接阵接口) 317. 最大流(邻接阵形式) 328. 最大流无流量(邻接阵形式) 329. 最小费用最大流(邻接阵形式) 33五. 图论_最短路径341. 最短路径(单源bellman_ford邻接阵形式) 342. 最短路径(单源dijkstra_bfs邻接表形式) 353. 最短路径(单源dijkstra_bfs正向表形式) 354. 最短路径(单源dijkstra+binary_heap邻接表形式) 365. 最短路径(单源dijkstra+binary_heap正向表形式) 376. 最短路径(单源dijkstra+mapped_heap邻接表形式) 387. 最短路径(单源dijkstra+mapped_heap正向表形式) 398. 最短路径(单源dijkstra邻接阵形式) 409. 最短路径(多源floyd_warshall邻接阵形式) 40六. 图论_连通性411. 无向图关键边(dfs邻接阵形式) 412. 无向图关键点(dfs邻接阵形式) 423. 无向图块(bfs邻接阵形式) 434. 无向图连通分支(bfs邻接阵形式) 435. 无向图连通分支(dfs邻接阵形式) 446. 有向图强连通分支(bfs邻接阵形式) 447. 有向图强连通分支(dfs邻接阵形式) 458. 有向图最小点基(邻接阵形式) 46七. 图论_应用461.欧拉回路(邻接阵形式) 462. 前序表转化473. 树的优化算法484. 拓扑排序(邻接阵形式). 495. 最佳边割集506. 最佳顶点割集517. 最小边割集528. 最小顶点割集539. 最小路径覆盖55八. 图论_NP搜索551. 最大团(n小于64)(faster) 552. 最大团58九. 组合591. 排列组合生成592. 生成gray码603. 置换(polya) 614. 字典序全排列615. 字典序组合626. 组合公式62十. 数值计算631. 定积分计算(Romberg) 632. 多项式求根(牛顿法) 643. 周期性方程(追赶法) 66十一. 几何671. 多边形672. 多边形切割703. 浮点函数714. 几何公式765. 面积786. 球面797. 三角形798. 三维几何819. 凸包(graham) 8910. 网格(pick) 9111. 圆9212. 整数函数9413. 注意96十二. 结构971. 并查集972. 并查集扩展(friend_enemy) 983. 堆(binary) 984. 堆(mapped) 995. 矩形切割996. 线段树1007. 线段树扩展1028. 线段树应用1059. 子段和10510. 子阵和105十三. 其他1061. 分数1062. 矩阵1083. 日期1104. 线性方程组(gauss) 1115. 线性相关113十四. 应用1141. joseph 1142. N皇后构造解 1153. 布尔母函数1154. 第k元素1165. 幻方构造1166. 模式匹配(kmp) 1187. 逆序对数1188. 字符串最小表示1199. 最长公共单调子序列11910. 最长子序列12011. 最大子串匹配12112. 最大子段和12213. 最大子阵和123一.数论1.阶乘最后非零位//求阶乘最后非零位,复杂度O(nlogn)//返回该位,n以字符串方式传入#include <string.h>#define MAXN 10000int lastdigit(char* buf){const int mod[20]={1,1,2,6,4,2,2,4,2,8,4,4,8,4,6,8,8,6,8,2};int len=strlen(buf),a[MAXN],i,c,ret=1;if (len==1)return mod[buf[0]-'0'];for (i=0;i<len;i++)a[i]=buf[len-1-i]-'0';for (;len;len-=!a[len-1]){ret=ret*mod[a[1]%2*10+a[0]]%5;for (c=0,i=len-1;i>=0;i--)c=c*10+a[i],a[i]=c/5,c%=5;}return ret+ret%2*5;}2. 模线性方程(组)#ifdef WIN32typedef __int64 i64;#elsetypedef long long i64;#endif//扩展Euclid求解gcd(a,b)=ax+byint ext_gcd(int a,int b,int& x,int& y){int t,ret;if (!b){x=1,y=0;return a;}ret=ext_gcd(b,a%b,x,y);t=x,x=y,y=t-a/b*y;return ret;}//计算m^a, O(loga), 本身没什么用, 注意这个按位处理的方法:-Pint exponent(int m,int a){int ret=1;for (;a;a>>=1,m*=m)if (a&1)ret*=m;return ret;}//计算幂取模a^b mod n, O(logb)int modular_exponent(int a,int b,int n){ //a^b mod nint ret=1;for (;b;b>>=1,a=(int)((i64)a)*a%n)if (b&1)ret=(int)((i64)ret)*a%n;return ret;}//求解模线性方程ax=b (mod n)//返回解的个数,解保存在sol[]中//要求n>0,解的范围0..n-1int modular_linear(int a,int b,int n,int* sol){int d,e,x,y,i;d=ext_gcd(a,n,x,y);if (b%d)return 0;e=(x*(b/d)%n+n)%n;for (i=0;i<d;i++)sol[i]=(e+i*(n/d))%n;return d;}//求解模线性方程组(中国余数定理)// x = b[0] (mod w[0])// x = b[1] (mod w[1])// ...// x = b[k-1] (mod w[k-1])//要求w[i]>0,w[i]与w[j]互质,解的范围1..n,n=w[0]*w[1]*...*w[k-1]int modular_linear_system(int b[],int w[],int k){int d,x,y,a=0,m,n=1,i;for (i=0;i<k;i++)n*=w[i];for (i=0;i<k;i++){m=n/w[i];d=ext_gcd(w[i],m,x,y);a=(a+y*m*b[i])%n;}return (a+n)%n;}3. 素数表//用素数表判定素数,先调用initprimeint plist[10000],pcount=0;int prime(int n){int i;if((n!=2&&!(n%2))||(n!=3&&!(n%3))||(n!=5&&!(n%5))||(n!=7&&! (n%7)))return 0;for (i=0;plist[i]*plist[i]<=n;i++)if (!(n%plist[i]))return 0;return n>1;}void initprime(){int i;for (plist[pcount++]=2,i=3;i<50000;i++)if (prime(i))plist[pcount++]=i;}4. 素数随机判定(miller_rabin)//miller rabin//判断自然数n是否为素数//time越高失败概率越低,一般取10到50#include <stdlib.h>#ifdef WIN32typedef __int64 i64;#elsetypedef long long i64;#endifint modular_exponent(int a,int b,int n){ //a^b mod nint ret;for (;b;b>>=1,a=(int)((i64)a)*a%n)if (b&1)ret=(int)((i64)ret)*a%n;return ret;}// Carmicheal number: 561,41041,,int miller_rabin(int n,int time=10){if(n==1||(n!=2&&!(n%2))||(n!=3&&!(n%3))||(n!=5&&!(n%5))||(n!= 7&&!(n%7)))return 0;while (time--)if(modular_exponent(((rand()&0x7fff<<16)+rand()&0x7fff+rand() &0x7fff)%(n-1)+1,n-1,n)!=1)return 0;return 1;}5. 质因数分解//分解质因数//prime_factor()传入n, 返回不同质因数的个数//f存放质因数,nf存放对应质因数的个数//先调用initprime(),其中第二个initprime()更快#include<iostream>#include<cstdio>#include<cmath>using namespace std;#define MAXN#define PSIZEint plist[PSIZE], pcount=0;int prime(int n){int i;if((n!=2&&!(n%2))||(n!=3&&!(n%3))||(n!=5&&!(n%5))||(n!=7&&! (n%7)))return 0;for (i=0;plist[i]*plist[i]<=n;++i)if (!(n%plist[i]))return 0;return n>1;}void initprime(){int i;for (plist[pcount++]=2,i=3;i<;++i)if (prime(i))plist[pcount++]=i;}int prime_factor(int n, int* f, int *nf) {int cnt = 0;int n2 = sqrt((double)n);for(int i = 0; n > 1 && plist[i] <= n2; ++i)if (n % plist[i] == 0) {for (nf[cnt] = 0; n % plist[i] == 0; ++nf[cnt], n /= plist[i]);f[cnt++] = plist[i];}if (n > 1) nf[cnt] = 1, f[cnt++] = n;return cnt;}/*//产生MAXN以内的所有素数//note:就是//给所有2的倍数赋初值#include <cmath>#include <iostream>using namespace std;#define MAXNunsigned int plist[],pcount;unsigned int isprime[(MAXN>>5)+1];#define setbitzero(a) (isprime[(a)>>5]&=(~(1<<((a)&31))))#define setbitone(a) (isprime[(a)>>5]|=(1<<((a)&31)))#define ISPRIME(a) (isprime[(a)>>5]&(1<<((a)&31)))void initprime(){int i,j,m;int t=(MAXN>>5)+1;for(i=0;i<t;++i)isprime[i]=;plist[0]=2;setbitone(2);setbitzero(1);m=(int)sqrt(MAXN);for(pcount=1,i=3;i<=m;i+=2)if(ISPRIME(i))for(plist[pcount++]=i,j=i<<1;j<=MAXN;j+=i)setbitzero(j);if(!(i&1))++i;for(;i<=MAXN;i+=2)if(ISPRIME(i))plist[pcount++]=i;}6. 最大公约数欧拉函数int gcd(int a,int b){return b?gcd(b,a%b):a;}inline int lcm(int a,int b){return a/gcd(a,b)*b;}//求1..n-1中与n互质的数的个数int eular(int n){int ret=1,i;for (i=2;i*i<=n;i++)if (n%i==0){n/=i,ret*=i-1;while (n%i==0)n/=i,ret*=i;}if (n>1)ret*=n-1;return ret;}二.图论_匹配1. 二分图最大匹配(hungary邻接表形式)//二分图最大匹配,hungary算法,邻接表形式,复杂度O(m*e)//返回最大匹配数,传入二分图大小m,n和邻接表list(只需一边) //match1,match2返回一个最大匹配,未匹配顶点match值为-1 #include <string.h>#define MAXN 310#define _clr(x) memset(x,0xff,sizeof(int)*MAXN)struct edge_t{int from,to;edge_t* next;};int hungary(int m,int n,edge_t* list[],int* match1,int* match2){ int s[MAXN],t[MAXN],p,q,ret=0,i,j,k;edge_t* e;for(_clr(match1),_clr(match2),i=0;i<m;ret+=(match1[i++]>=0))for (_clr(t),s[p=q=0]=i;p<=q&&match1[i]<0;p++)for (e=list[k=s[p]];e&&match1[i]<0;e=e->next)if (t[j=e->to]<0){s[++q]=match2[j],t[j]=k;if (s[q]<0)for (p=j;p>=0;j=p)match2[j]=k=t[j],p=match1[k],match1[k]=j;}return ret; }2. 二分图最大匹配(hungary邻接表形式,邻接阵接口)//二分图最大匹配,hungary算法,邻接表形式,邻接阵接口,复杂度O(m*e)s//返回最大匹配数,传入二分图大小m,n和邻接阵//match1,match2返回一个最大匹配,未匹配顶点match值为-1 #include <string.h>#include <vector>#define MAXN 310#define _clr(x) memset(x,0xff,sizeof(int)*MAXN)int hungary(int m,int n,int mat[][MAXN],int* match1,int*match2){int s[MAXN],t[MAXN],p,q,ret=0,i,j,k,r;vector<int> e[MAXN];//生成邻接表(只需一边)for(i=0;i<m;++i)for(j=0;j<n;++j)if (mat[i][j]) e[i].push_back(j);for(_clr(match1),_clr(match2),i=0;i<m;ret+=(match1[i++]>=0))for (_clr(t),s[p=q=0]=i;p<=q&&match1[i]<0;p++)for(r=0,k=s[p];r<e[k].size()&&match1[i]<0;++r)if (t[j=e[k][r]]<0){s[++q]=match2[j],t[j]=k;if (s[q]<0)for (p=j;p>=0;j=p)match2[j]=k=t[j],p=match1[k],match1[k]=j;}return ret;}3. 二分图最大匹配(hungary邻接阵形式)//二分图最大匹配,hungary算法,邻接阵形式,复杂度O(m*m*n) //返回最大匹配数,传入二分图大小m,n和邻接阵mat,非零元素表示有边//match1,match2返回一个最大匹配,未匹配顶点match值为-1 #include <string.h>#define MAXN 310#define _clr(x) memset(x,0xff,sizeof(int)*MAXN)int hungary(int m,int n,int mat[][MAXN],int* match1,int*match2){int s[MAXN],t[MAXN],p,q,ret=0,i,j,k;for(_clr(match1),_clr(match2),i=0;i<m;ret+=(match1[i++]>=0))for (_clr(t),s[p=q=0]=i;p<=q&&match1[i]<0;p++)for (k=s[p],j=0;j<n&&match1[i]<0;j++)if (mat[k][j]&&t[j]<0){s[++q]=match2[j],t[j]=k;if (s[q]<0)for (p=j;p>=0;j=p)match2[j]=k=t[j],p=match1[k],match1[k]=j;}return ret;}4. 二分图最大匹配(hungary正向表形式)//二分图最大匹配,hungary算法,正向表形式,复杂度O(m*e)//返回最大匹配数,传入二分图大小m,n和正向表list,buf(只需一边)//match1,match2返回一个最大匹配,未匹配顶点match值为-1 #include <string.h>#define MAXN 310#define _clr(x) memset(x,0xff,sizeof(int)*MAXN)int hungary(int m,int n,int* list,int* buf,int* match1,int* match2){ int s[MAXN],t[MAXN],p,q,ret=0,i,j,k,l;for(_clr(match1),_clr(match2),i=0;i<m;ret+=(match1[i++]>=0))for (_clr(t),s[p=q=0]=i;p<=q&&match1[i]<0;p++)for(l=list[k=s[p]];l<list[k+1]&&match1[i]<0;l++)if (t[j=buf[l]]<0){s[++q]=match2[j],t[j]=k;if (s[q]<0)for (p=j;p>=0;j=p)match2[j]=k=t[j],p=match1[k],match1[k]=j;}return ret;}5. 二分图最佳匹配(kuhn_munkras邻接阵形式)//二分图最佳匹配,kuhn munkras算法,邻接阵形式,复杂度O(m*m*n)//返回最佳匹配值,传入二分图大小m,n和邻接阵mat,表示权值//match1,match2返回一个最佳匹配,未匹配顶点match值为-1 //一定注意m<=n,否则循环无法终止//最小权匹配可将权值取相反数#include <string.h>#define MAXN 310#define inf#define _clr(x) memset(x,0xff,sizeof(int)*n)int kuhn_munkras(int m,int n,int mat[][MAXN],int* match1,int* match2){ints[MAXN],t[MAXN],l1[MAXN],l2[MAXN],p,q,ret=0,i,j,k;for (i=0;i<m;i++)for (l1[i]=-inf,j=0;j<n;j++)l1[i]=mat[i][j]>l1[i]?mat[i][j]:l1[i];for (i=0;i<n;l2[i++]=0);for (_clr(match1),_clr(match2),i=0;i<m;i++){for (_clr(t),s[p=q=0]=i;p<=q&&match1[i]<0;p++)for (k=s[p],j=0;j<n&&match1[i]<0;j++)if (l1[k]+l2[j]==mat[k][j]&&t[j]<0){s[++q]=match2[j],t[j]=k;if (s[q]<0)for (p=j;p>=0;j=p)match2[j]=k=t[j],p=match1[k],match1[k]=j;}if (match1[i]<0){for (i--,p=inf,k=0;k<=q;k++)for (j=0;j<n;j++)if(t[j]<0&&l1[s[k]]+l2[j]-mat[s[k]][j]<p)p=l1[s[k]]+l2[j]-mat[s[k]][j];for (j=0;j<n;l2[j]+=t[j]<0?0:p,j++);for (k=0;k<=q;l1[s[k++]]-=p);}}for (i=0;i<m;i++)ret+=mat[i][match1[i]];return ret;}6. 一般图匹配(邻接表形式)//一般图最大匹配,邻接表形式,复杂度O(n*e)//返回匹配顶点对数,match返回匹配,未匹配顶点match值为-1 //传入图的顶点数n和邻接表list#define MAXN 100struct edge_t{int from,to;edge_t* next;};int aug(int n,edge_t* list[],int* match,int* v,int now){int t,ret=0;edge_t* e;v[now]=1;for (e=list[now];e;e=e->next)if (!v[t=e->to]){if (match[t]<0)match[now]=t,match[t]=now,ret=1;else{v[t]=1;if (aug(n,list,match,v,match[t]))match[now]=t,match[t]=now,ret=1;v[t]=0;}if (ret)break;}v[now]=0;return ret;}int graph_match(int n,edge_t* list[],int* match){int v[MAXN],i,j;for (i=0;i<n;i++)v[i]=0,match[i]=-1;for (i=0,j=n;i<n&&j>=2;)if (match[i]<0&&aug(n,list,match,v,i))i=0,j-=2;elsei++;for (i=j=0;i<n;i++)j+=(match[i]>=0);return j/2;}7. 一般图匹配(邻接表形式,邻接阵接口)//一般图最大匹配,邻接表形式,复杂度O(n*e)//返回匹配顶点对数,match返回匹配,未匹配顶点match值为-1 //传入图的顶点数n和邻接表list#include <vector>#define MAXN 100int aug(int n,vector<int> list[],int* match,int* v,int now){ int t,ret=0,r;v[now]=1;// for (e=list[now];e;e=e->next)for (r=0;r<list[now].size();++r)if (!v[t=list[now][r]]){if (match[t]<0)match[now]=t,match[t]=now,ret=1;else{v[t]=1;if (aug(n,list,match,v,match[t]))match[now]=t,match[t]=now,ret=1;v[t]=0;}if (ret)break;}v[now]=0;return ret;}int graph_match(int n,int mat[][MAXN],int* match){int v[MAXN],i,j;vector<int> list[MAXN];for (i=0;i<n;i++)for (j=0;j<n;j++)if (mat[i][j]) list[i].push_back(j);for (i=0;i<n;i++)v[i]=0,match[i]=-1;for (i=0,j=n;i<n&&j>=2;)if (match[i]<0&&aug(n,list,match,v,i))i=0,j-=2;elsei++;for (i=j=0;i<n;i++)j+=(match[i]>=0);return j/2;}8. 一般图匹配(邻接阵形式)//一般图最大匹配,邻接阵形式,复杂度O(n^3)//返回匹配顶点对数,match返回匹配,未匹配顶点match值为-1 //传入图的顶点数n和邻接阵mat#define MAXN 100int aug(int n,int mat[][MAXN],int* match,int* v,int now){ int i,ret=0;v[now]=1;for (i=0;i<n;i++)if (!v[i]&&mat[now][i]){if (match[i]<0)match[now]=i,match[i]=now,ret=1;else{v[i]=1;if (aug(n,mat,match,v,match[i]))match[now]=i,match[i]=now,ret=1;v[i]=0;}if (ret)break;}v[now]=0;return ret;}int graph_match(int n,int mat[][MAXN],int* match){int v[MAXN],i,j;for (i=0;i<n;i++)v[i]=0,match[i]=-1;for (i=0,j=n;i<n&&j>=2;)if (match[i]<0&&aug(n,mat,match,v,i))i=0,j-=2;elsei++;for (i=j=0;i<n;i++)j+=(match[i]>=0);return j/2;}9. 一般图匹配(正向表形式)//一般图最大匹配,正向表形式,复杂度O(n*e)//返回匹配顶点对数,match返回匹配,未匹配顶点match值为-1 //传入图的顶点数n和正向表list,buf#define MAXN 100int aug(int n,int* list,int* buf,int* match,int* v,int now){ int i,t,ret=0;v[now]=1;for (i=list[now];i<list[now+1];i++)if (!v[t=buf[i]]){if (match[t]<0)match[now]=t,match[t]=now,ret=1;else{v[t]=1;if (aug(n,list,buf,match,v,match[t]))match[now]=t,match[t]=now,ret=1;v[t]=0;}if (ret)break;}v[now]=0;return ret;}int graph_match(int n,int* list,int* buf,int* match){int v[MAXN],i,j;for (i=0;i<n;i++)v[i]=0,match[i]=-1;for (i=0,j=n;i<n&&j>=2;)if (match[i]<0&&aug(n,list,buf,match,v,i))i=0,j-=2;elsei++;for (i=j=0;i<n;i++)j+=(match[i]>=0);return j/2;}三.图论_生成树1. 最小生成树(kruskal邻接表形式)//无向图最小生成树,kruskal算法,邻接表形式,复杂度O(mlogm) //返回最小生成树的长度,传入图的大小n和邻接表list//可更改边权的类型,edge[][2]返回树的构造,用边集表示//如果图不连通,则对各连通分支构造最小生成树,返回总长度#include <string.h>#define MAXN 200#define inftypedef double elem_t;struct edge_t{int from,to;elem_t len;edge_t* next;};#define _ufind_run(x) for(;p[t=x];x=p[x],p[t]=(p[x]?p[x]:x))#define _run_both _ufind_run(i);_ufind_run(j)struct ufind{int p[MAXN],t;void init(){memset(p,0,sizeof(p));}void set_friend(int i,int j){_run_both;p[i]=(i==j?0:j);}int is_friend(int i,int j){_run_both;return i==j&&i;}};#define _cp(a,b) ((a).len<(b).len)struct heap_t{int a,b;elem_t len;};struct minheap{heap_t h[MAXN*MAXN];int n,p,c;void init(){n=0;}void ins(heap_t e){for(p=++n;p>1&&_cp(e,h[p>>1]);h[p]=h[p>>1],p>>=1);h[p]=e;}int del(heap_t& e){if (!n) return 0;for(e=h[p=1],c=2;c<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n ]);h[p]=h[c],p=c,c<<=1);h[p]=h[n--];return 1;}};elem_t kruskal(int n,edge_t* list[],int edge[][2]){ufind u;minheap h;edge_t* t;heap_t e;elem_t ret=0;int i,m=0;u.init(),h.init();for (i=0;i<n;i++)for (t=list[i];t;t=t->next)if (i<t->to)e.a=i,e.b=t->to,e.len=t->len,h.ins(e);while (m<n-1&&h.del(e))if (!u.is_friend(e.a+1,e.b+1))edge[m][0]=e.a,edge[m][1]=e.b,ret+=e.len,u.set_friend(e.a+ 1,e.b+1);return ret;}2. 最小生成树(kruskal正向表形式)//无向图最小生成树,kruskal算法,正向表形式,复杂度O(mlogm) //返回最小生成树的长度,传入图的大小n和正向表list,buf//可更改边权的类型,edge[][2]返回树的构造,用边集表示//如果图不连通,则对各连通分支构造最小生成树,返回总长度#include <string.h>#define MAXN 200#define inftypedef double elem_t;struct edge_t{int to;elem_t len;};#define _ufind_run(x) for(;p[t=x];x=p[x],p[t]=(p[x]?p[x]:x))#define _run_both _ufind_run(i);_ufind_run(j)struct ufind{int p[MAXN],t;void init(){memset(p,0,sizeof(p));}void set_friend(int i,int j){_run_both;p[i]=(i==j?0:j);}int is_friend(int i,int j){_run_both;return i==j&&i;}};#define _cp(a,b) ((a).len<(b).len)struct heap_t{int a,b;elem_t len;};struct minheap{heap_t h[MAXN*MAXN];int n,p,c;void init(){n=0;}void ins(heap_t e){for(p=++n;p>1&&_cp(e,h[p>>1]);h[p]=h[p>>1],p>>=1);h[p]=e;}int del(heap_t& e){if (!n) return 0;for(e=h[p=1],c=2;c<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n ]);h[p]=h[c],p=c,c<<=1);h[p]=h[n--];return 1;}};elem_t kruskal(int n,int* list,edge_t* buf,int edge[][2]){ ufind u;minheap h;heap_t e;elem_t ret=0;int i,j,m=0;u.init(),h.init();for (i=0;i<n;i++)for (j=list[i];j<list[i+1];j++)if (i<buf[j].to)e.a=i,e.b=buf[j].to,e.len=buf[j].len,h.ins(e);while (m<n-1&&h.del(e))if (!u.is_friend(e.a+1,e.b+1))edge[m][0]=e.a,edge[m][1]=e.b,ret+=e.len,u.set_friend(e.a+ 1,e.b+1);return ret;}3. 最小生成树(prim+binary_heap邻接表形式)//无向图最小生成树,prim算法+二分堆,邻接表形式,复杂度O(mlogm)//返回最小生成树的长度,传入图的大小n和邻接表list//可更改边权的类型,pre[]返回树的构造,用父结点表示,根节点(第一个)pre值为-1//必须保证图的连通的!#define MAXN 200#define inftypedef double elem_t;struct edge_t{int from,to;elem_t len;edge_t* next;};#define _cp(a,b) ((a).d<(b).d)struct heap_t{elem_t d;int v;};struct heap{heap_t h[MAXN*MAXN];int n,p,c;void init(){n=0;}void ins(heap_t e){for(p=++n;p>1&&_cp(e,h[p>>1]);h[p]=h[p>>1],p>>=1);h[p]=e;}int del(heap_t& e){if (!n) return 0;for(e=h[p=1],c=2;c<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n ]);h[p]=h[c],p=c,c<<=1);h[p]=h[n--];return 1;}};elem_t prim(int n,edge_t* list[],int* pre){heap h;elem_t min[MAXN],ret=0;edge_t* t;heap_t e;int v[MAXN],i;for (i=0;i<n;i++)min[i]=inf,v[i]=0,pre[i]=-1;h.init();e.v=0,e.d=0,h.ins(e);while (h.del(e))if (!v[e.v])for (v[e.v]=1,ret+=e.d,t=list[e.v];t;t=t->next)if (!v[t->to]&&t->len<min[t->to])pre[t->to]=t->from,min[e.v=t->to]=e.d=t->len,h.ins(e);return ret;}4. 最小生成树(prim+binary_heap正向表形式)//无向图最小生成树,prim算法+二分堆,正向表形式,复杂度O(mlogm)//返回最小生成树的长度,传入图的大小n和正向表list,buf//可更改边权的类型,pre[]返回树的构造,用父结点表示,根节点(第一个)pre值为-1//必须保证图的连通的!#define MAXN 200#define inftypedef double elem_t;struct edge_t{int to;elem_t len;};#define _cp(a,b) ((a).d<(b).d)struct heap_t{elem_t d;int v;};struct heap{heap_t h[MAXN*MAXN];int n,p,c;void init(){n=0;}void ins(heap_t e){for(p=++n;p>1&&_cp(e,h[p>>1]);h[p]=h[p>>1],p>>=1);h[p]=e;}int del(heap_t& e){if (!n) return 0;for(e=h[p=1],c=2;c<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n ]);h[p]=h[c],p=c,c<<=1);h[p]=h[n--];return 1;}};elem_t prim(int n,int* list,edge_t* buf,int* pre){heap h;heap_t e;elem_t min[MAXN],ret=0;int v[MAXN],i,j;for (i=0;i<n;i++)min[i]=inf,v[i]=0,pre[i]=-1;h.init();e.v=0,e.d=0,h.ins(e);while (h.del(e))if (!v[i=e.v])for (v[i]=1,ret+=e.d,j=list[i];j<list[i+1];j++)if(!v[buf[j].to]&&buf[j].len<min[buf[j].to])pre[buf[j].to]=i,min[e.v=buf[j].to]=e.d=buf[j].len,h.ins(e);return ret;}5. 最小生成树(prim+mapped_heap邻接表形式)//无向图最小生成树,prim算法+映射二分堆,邻接表形式,复杂度O(mlogn)//返回最小生成树的长度,传入图的大小n和邻接表list//可更改边权的类型,pre[]返回树的构造,用父结点表示,根节点(第一个)pre值为-1//必须保证图的连通的!#define MAXN 200#define inftypedef double elem_t;struct edge_t{int from,to;elem_t len;edge_t* next;};#define _cp(a,b) ((a)<(b))struct heap{elem_t h[MAXN+1];int ind[MAXN+1],map[MAXN+1],n,p,c;void init(){n=0;}void ins(int i,elem_t e){for(p=++n;p>1&&_cp(e,h[p>>1]);h[map[ind[p]=ind[p>>1]]=p]=h[p >>1],p>>=1);h[map[ind[p]=i]=p]=e;}int del(int i,elem_t& e){i=map[i];if (i<1||i>n) return 0;for(e=h[p=i];p>1;h[map[ind[p]=ind[p>>1]]=p]=h[p>>1],p>>=1);for(c=2;c<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n]);h[map[i nd[p]=ind[c]]=p]=h[c],p=c,c<<=1);h[map[ind[p]=ind[n]]=p]=h[n];n--;return 1;}int delmin(int& i,elem_t& e){if (n<1) return 0;i=ind[1];for(e=h[p=1],c=2;c<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n ]);h[map[ind[p]=ind[c]]=p]=h[c],p=c,c<<=1);h[map[ind[p]=ind[n]]=p]=h[n];n--;return 1;}};elem_t prim(int n,edge_t* list[],int* pre){heap h;elem_t min[MAXN],ret=0,e;edge_t* t;int v[MAXN],i;for (h.init(),i=0;i<n;i++)min[i]=(i?inf:0),v[i]=0,pre[i]=-1,h.ins(i,min[i]);while (h.delmin(i,e))for (v[i]=1,ret+=e,t=list[i];t;t=t->next)if (!v[t->to]&&t->len<min[t->to])pre[t->to]=t->from,h.del(t->to,e),h.ins(t->to,min[t->to]=t->l en);return ret; }6. 最小生成树(prim+mapped_heap正向表形式)//无向图最小生成树,prim算法+映射二分堆,正向表形式,复杂度O(mlogn)//返回最小生成树的长度,传入图的大小n和正向表list,buf//可更改边权的类型,pre[]返回树的构造,用父结点表示,根节点(第一个)pre值为-1//必须保证图的连通的!#define MAXN 200#define inftypedef double elem_t;struct edge_t{int to;elem_t len;};#define _cp(a,b) ((a)<(b))struct heap{elem_t h[MAXN+1];int ind[MAXN+1],map[MAXN+1],n,p,c;void init(){n=0;}void ins(int i,elem_t e){for(p=++n;p>1&&_cp(e,h[p>>1]);h[map[ind[p]=ind[p>>1]]=p]=h[p >>1],p>>=1);h[map[ind[p]=i]=p]=e;}int del(int i,elem_t& e){i=map[i];if (i<1||i>n) return 0;for(e=h[p=i];p>1;h[map[ind[p]=ind[p>>1]]=p]=h[p>>1],p>>=1);for(c=2;c<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n]);h[map[i nd[p]=ind[c]]=p]=h[c],p=c,c<<=1);h[map[ind[p]=ind[n]]=p]=h[n];n--;return 1;}int delmin(int& i,elem_t& e){if (n<1) return 0;i=ind[1];for(e=h[p=1],c=2;c<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n ]);h[map[ind[p]=ind[c]]=p]=h[c],p=c,c<<=1);h[map[ind[p]=ind[n]]=p]=h[n];n--;return 1;}};elem_t prim(int n,int* list,edge_t* buf,int* pre){heap h;elem_t min[MAXN],ret=0,e;int v[MAXN],i,j;for (h.init(),i=0;i<n;i++)min[i]=(i?inf:0),v[i]=0,pre[i]=-1,h.ins(i,min[i]);while (h.delmin(i,e))for (v[i]=1,ret+=e,j=list[i];j<list[i+1];j++)if (!v[buf[j].to]&&buf[j].len<min[buf[j].to]) pre[buf[j].to]=i,h.del(buf[j].to,e),h.ins(buf[j].to,min[buf[j].to ]=buf[j].len);return ret;}7. 最小生成树(prim邻接阵形式)//无向图最小生成树,prim算法,邻接阵形式,复杂度O(n^2)//返回最小生成树的长度,传入图的大小n和邻接阵mat,不相邻点边权inf//可更改边权的类型,pre[]返回树的构造,用父结点表示,根节点(第一个)pre值为-1//必须保证图的连通的!#define MAXN 200#define inftypedef double elem_t;elem_t prim(int n,elem_t mat[][MAXN],int* pre){elem_t min[MAXN],ret=0;int v[MAXN],i,j,k;for (i=0;i<n;i++)min[i]=inf,v[i]=0,pre[i]=-1;for (min[j=0]=0;j<n;j++){for (k=-1,i=0;i<n;i++)if (!v[i]&&(k==-1||min[i]<min[k]))k=i;for (v[k]=1,ret+=min[k],i=0;i<n;i++)if (!v[i]&&mat[k][i]<min[i])min[i]=mat[pre[i]=k][i];}return ret;}8. 最小树形图(邻接阵形式)//多源最小树形图,edmonds算法,邻接阵形式,复杂度O(n^3)//返回最小生成树的长度,构造失败返回负值//传入图的大小n和邻接阵mat,不相邻点边权inf//可更改边权的类型,pre[]返回树的构造,用父结点表示//传入时pre[]数组清零,用-1标出源点#include <string.h>#define MAXN 120#define inftypedef int elem_t;elem_t edmonds(int n,elem_t mat[][MAXN*2],int* pre){ elem_t ret=0;intc[MAXN*2][MAXN*2],l[MAXN*2],p[MAXN*2],m=n,t,i,j,k;for (i=0;i<n;l[i]=i,i++);do{memset(c,0,sizeof(c)),memset(p,0xff,sizeof(p));for (t=m,i=0;i<m;c[i][i]=1,i++);for (i=0;i<t;i++)if (l[i]==i&&pre[i]!=-1){for (j=0;j<m;j++)if(l[j]==j&&i!=j&&mat[j][i]<inf&&(p[i]==-1||mat[j][i]<mat[p[i]][i ]))p[i]=j;if ((pre[i]=p[i])==-1)return -1;if (c[i][p[i]]){for(j=0;j<=m;mat[j][m]=mat[m][j]=inf,j++);for (k=i;l[k]!=m;l[k]=m,k=p[k])for (j=0;j<m;j++)if (l[j]==j){if(mat[j][k]-mat[p[k]][k]<mat[j][m])mat[j][m]=mat[j][k]-mat[p[k]][k];if(mat[k][j]<mat[m][j])mat[m][j]=mat[k][j];}c[m][m]=1,l[m]=m,m++;}for (j=0;j<m;j++)if (c[i][j])for(k=p[i];k!=-1&&l[k]==k;c[k][j]=1,k=p[k]);}}while (t<m);for (;m-->n;pre[k]=pre[m])for (i=0;i<m;i++)if (l[i]==m){for (j=0;j<m;j++)if(pre[j]==m&&mat[i][j]==mat[m][j])pre[j]=i;if(mat[pre[m]][m]==mat[pre[m]][i]-mat[pre[i]][i])k=i;}for (i=0;i<n;i++)if (pre[i]!=-1)ret+=mat[pre[i]][i];return ret;}四.图论_网络流1. 上下界最大流(邻接表形式)//求上下界网络最大流,邻接表形式//返回最大流量,-1表示无可行流,flow返回每条边的流量//传入网络节点数n,容量mat,流量下界bf,源点source,汇点sink //MAXN应比最大结点数多2,无可行流返回-1时mat未复原! #define MAXN 100#define infint _max_flow(int n,int mat[][MAXN],int source,int sink,intflow[][MAXN]){int pre[MAXN],que[MAXN],d[MAXN],p,q,t,i,j,r;vector<int> e[MAXN];for (i=0;i<n;i++)for (e[i].clear(),j=0;j<n;j++)if (mat[i][j]) e[i].push_back(j),e[j].push_back(i);for (;;){for (i=0;i<n;pre[i++]=0);pre[t=source]=source+1,d[t]=inf;for (p=q=0;p<=q&&!pre[sink];t=que[p++])for (r=0;r<e[t].size();++r){i=e[t][r];if (!pre[i]&&(j=mat[t][i]-flow[t][i])) pre[que[q++]=i]=t+1,d[i]=d[t]<j?d[t]:j;else if (!pre[i]&&(j=flow[i][t]))pre[que[q++]=i]=-t-1,d[i]=d[t]<j?d[t]:j;}if (!pre[sink]) break;for (i=sink;i!=source;)if (pre[i]>0)flow[pre[i]-1][i]+=d[sink],i=pre[i]-1;elseflow[i][-pre[i]-1]-=d[sink],i=-pre[i]-1;}for (j=i=0;i<n;j+=flow[source][i++]);return j;}int limit_max_flow(int n,int mat[][MAXN],int bf[][MAXN],int source,int sink,int flow[][MAXN]){int i,j,sk,ks;if (source==sink) return inf;for(mat[n][n+1]=mat[n+1][n]=mat[n][n]=mat[n+1][n+1]=i=0;i<n;i+ +)for(mat[n][i]=mat[i][n]=mat[n+1][i]=mat[i][n+1]=j=0;j<n;j++) mat[i][j]-=bf[i][j],mat[n][i]+=bf[j][i],mat[i][n+1]+=bf[i][j];sk=mat[source][sink],ks=mat[sink][source],mat[source][sink ]=mat[sink][source]=inf;for (i=0;i<n+2;i++)for (j=0;j<n+2;flow[i][j++]=0);_max_flow(n+2,mat,n,n+1,flow);for (i=0;i<n;i++)if (flow[n][i]<mat[n][i]) return -1;flow[source][sink]=flow[sink][source]=0,mat[source][sink] =sk,mat[sink][source]=ks;_max_flow(n,mat,source,sink,flow);for (i=0;i<n;i++)for (j=0;j<n;j++)mat[i][j]+=bf[i][j],flow[i][j]+=bf[i][j];for (j=i=0;i<n;j+=flow[source][i++]);return j;}2. 上下界最大流(邻接阵形式)//求上下界网络最大流,邻接阵形式//返回最大流量,-1表示无可行流,flow返回每条边的流量//传入网络节点数n,容量mat,流量下界bf,源点source,汇点sink //MAXN应比最大结点数多2,无可行流返回-1时mat未复原! #define MAXN 100#define inf void _max_flow(int n,int mat[][MAXN],int source,int sink,int flow[][MAXN]){int pre[MAXN],que[MAXN],d[MAXN],p,q,t,i,j;for (;;){for (i=0;i<n;pre[i++]=0);pre[t=source]=source+1,d[t]=inf;for (p=q=0;p<=q&&!pre[sink];t=que[p++])for (i=0;i<n;i++)if (!pre[i]&&j=mat[t][i]-flow[t][i]) pre[que[q++]=i]=t+1,d[i]=d[t]<j?d[t]:j;else if (!pre[i]&&j=flow[i][t])pre[que[q++]=i]=-t-1,d[i]=d[t]<j?d[t]:j;if (!pre[sink]) break;for (i=sink;i!=source;)if (pre[i]>0)flow[pre[i]-1][i]+=d[sink],i=pre[i]-1;elseflow[i][-pre[i]-1]-=d[sink],i=-pre[i]-1;}}int limit_max_flow(int n,int mat[][MAXN],int bf[][MAXN],int source,int sink,int flow[][MAXN]){int i,j,sk,ks;if (source==sink) return inf;for(mat[n][n+1]=mat[n+1][n]=mat[n][n]=mat[n+1][n+1]=i=0;i<n;i+ +)for(mat[n][i]=mat[i][n]=mat[n+1][i]=mat[i][n+1]=j=0;j<n;j++) mat[i][j]-=bf[i][j],mat[n][i]+=bf[j][i],mat[i][n+1]+=bf[i][j];sk=mat[source][sink],ks=mat[sink][source],mat[source][sink ]=mat[sink][source]=inf;for (i=0;i<n+2;i++)for (j=0;j<n+2;flow[i][j++]=0);_max_flow(n+2,mat,n,n+1,flow);for (i=0;i<n;i++)if (flow[n][i]<mat[n][i]) return -1;flow[source][sink]=flow[sink][source]=0,mat[source][sink] =sk,mat[sink][source]=ks;_max_flow(n,mat,source,sink,flow);for (i=0;i<n;i++)for (j=0;j<n;j++)mat[i][j]+=bf[i][j],flow[i][j]+=bf[i][j];for (j=i=0;i<n;j+=flow[source][i++]);return j;}3. 上下界最小流(邻接表形式)//求上下界网络最小流,邻接阵形式//返回最大流量,-1表示无可行流,flow返回每条边的流量//传入网络节点数n,容量mat,流量下界bf,源点source,汇点sink //MAXN应比最大结点数多2,无可行流返回-1时mat未复原! #define MAXN 100#define inf。
ACM培训大纲

实用标准文案ACM培训大纲基础内容:数据结构——》搜索——》图论DP数论博弈中级内容数据结构网络流第一章搜索1.二分搜索三分搜索2.栈3.队列4.深搜5,广搜6.第二章数据结构1.优先队列并查集2.二叉搜索树3.线段树(单点更新)4.5.精彩文档.实用标准文案第三章图论1.图的表示1.1二维数组1.2邻接表1.3前向星2.图的遍历2.1双连通分量2. 2拓扑排序3.最短路3.1迪杰斯特拉3. 2弗洛伊德4. 3 SPFA5.匹配匈牙利算法6.生成树7.网络流简介第四章动态规划1.状态转移方程2.引入3. 1 0-1背包4.2硬币问题5. 3矩阵链乘6.区间DP7.按位DP8.树形DP9.状压DP第五章数论1.欧几里得扩展欧几里得2.因数分解3. 费马小定理4.欧拉定理5.6.1筛法6. 2素数判定6. 2,1 0(Jn)方法精彩文档.实用标准文案6. 2. 2 Mi I ler-rabin 测试第六章博弈1.Nim 和2.SG函数第七章中级数据结构1.树状数组RMO 2.KMP3.AC自动机4.线段树(区间更新)5.第八章图论进阶1.网络流问题精彩文档.实用标准文案综述在很多人眼里,东北大学秦皇岛分校不算是985高校。
所以我们要用自己的能力证明我们有985 的实力。
ACM是计算机界认可度最高的一个比赛,可以说只要区域赛有过奖牌,国内任何IT公司没有理由不要。
同时,在高校之中,对一个大学计算机专业的评价,大部分人也会首先看ACM 的水平。
将ACM打出学校,在国内打出一定成绩,对扩大我校影响力很有帮助。
考虑到本校暂时没有进行专题训练的出题能力,专题训练的题目主要从UESTC 2014年集训队专题训练中获取,再加上从别的0J上找一些题目。
训练的平台设置在华中科技大学的vertual judge上面。
本人将在毕业之前承担培训任务。
在2015学年开始之前,培训计划为每两周一次,中间空闲的时间由大二或者大一熟悉C++的同学给不熟悉C++的同学进行基础的讲解。
ACM中的数学应用

3.取模 ( mod) 用法及意义是:a≡b(mod c) 的意思是 a和b除以c后余 数相同 读作a与b同余,mod为c 例如:a mod b=c说明:a除以b余数为c
MOD (Pascal) % (C/C++/Java) 注意在计算机上使用取 模以后可能得到负值.
母猫的故事
有一只母猫,它每天早上生一头小母猫.每头小母猫从第2 天开始,每天早上也生一头小母猫.请编程实现在第n天的时 候,共有多少头母猫
……
3.有理数 4.实数/复数
基本代数1.gcd (最大公 Nhomakorabea数) 如果有一个自然数a能被自然数b整除,则称a为b的倍 数,b为a的约数.几个自然数公有的约数,叫做这几 个自然数的公约数.公约数中最大的一个公约数,称 为这几个自然数的最大公约数. 2.lcm(最小公倍数) 最小公倍数(Least Common Multiple,缩写L.C.M.), 对于两个正整数数来说,指该两数共有倍数中最小的 一个.计算最小公倍数时,通常会借助最大公约数来 辅助计算.
我们要从苹果,香蕉,橘子和梨中拿一些水果出 来,要求苹果只能拿偶数个,香蕉的个数要是5的倍数 ,橘子最多拿4个,梨要么不拿,要么只能拿一个.问 按这样的要求拿n个水果的方案数.
g(x)=(1+x^2+x^4+...)(1+x^5+x^10+..)(1+x+x^2+x^3+x^4)(1+x) =[1/(1-x^2)]*[1/(1-x^5)]*[(1-x^5)/(1-x)]*(1+x) (前两个分别是 公比为2和5的几何级数, 第三个嘛,(1+x+x^2+x^3+x^4)*(1-x)不就是1-x^5了吗) =1/(1-x)^2 (约分,把一大半都约掉了) =(1-x)^(-2)=C(1,0)+C(2,1)x+C(3,2)x^2+C(4,3)x^3... (参见 刚才对1/(1-x)^k的展开)
ACM大赛必备_常用函数整理_ACM模板

目录一、数学问题 (4)1.精度计算——大数阶乘 (4)2.精度计算——乘法(大数乘小数) (4)3.精度计算——乘法(大数乘大数) (5)4.精度计算——加法 (6)5.精度计算——减法 (7)6.任意进制转换 (8)7.最大公约数、最小公倍数 (9)8.组合序列 (10)9.快速傅立叶变换(FFT) (10)10.Ronberg 算法计算积分 (12)11.行列式计算 (14)12.求排列组合数 (15)13.求某一天星期几 (15)14.卡特兰(Catalan) 数列原理 (16)15.杨辉三角 (16)16.全排列 (17)17.匈牙利算法----最大匹配问题 (18)18.最佳匹配KM 算法 (20)二、字符串处理 (22)1.字符串替换 (22)2.字符串查找 (23)3.字符串截取 (24)4.LCS-最大公共子串长度 (24)5.LCS-最大公共子串长度 (25)6.数字转换为字符 (26)三、计算几何 (27)1.叉乘法求任意多边形面积 (27)2.求三角形面积 (27)3.两矢量间角度 (28)4.两点距离(2D、3D) (28)5.射向法判断点是否在多边形内部 (29)6.判断点是否在线段上 (30)7.判断两线段是否相交 (31)8.判断线段与直线是否相交 (32)9.点到线段最短距离 (32)10.求两直线的交点 (33)11.判断一个封闭图形是凹集还是凸集 (34)12.Graham 扫描法寻找凸包 (35)13.求两条线段的交点 (36)四、数论 (37)1.x 的二进制长度 (37)2.返回x 的二进制表示中从低到高的第i 位 (38)3.模取幂运算 (38)4.求解模线性方程 (39)5.求解模线性方程组(中国余数定理) (39)6.筛法素数产生器 (40)7.判断一个数是否素数 (41)8.求距阵最大和 (42)8.求一个数每一位相加之和 (43)10.质因数分解 (43)11.高斯消元法解线性方程组 (44)五、图论 (45)1.Prim 算法求最小生成树................................................. 45 2.Dijkstra 算法求单源最短路径.. (46)3.Bellman-ford 算法求单源最短路径 (47)4.Floyd-Warshall 算法求每对节点间最短路径 (48)5.解欧拉图 (49)六、排序/查找 (50)1.快速排序 (50)2.希尔排序 (51)3.选择法排序 (52)4.二分查找 (52)七、数据结构 (53)1.顺序队列 (53)2.顺序栈 (56)3.链表 (59)4.链栈 (63)5.二叉树 (66)八、高精度运算专题 (68)1.专题函数说明 (68)2.高精度数比较 (69)3.高精度数加法 (69)4.高精度数减法 (70)5.高精度乘10 (71)6.高精度乘单精度 (71)7.高精度乘高精度 (72)8.高精度除单精度 (72)9.高精度除高精度 (73)九、标准模板库的使用 (74)1.计算求和 (74)2.求数组中的最大值 (76)3. sort 和qsort (76)十、其他 (78)1.运行时间计算 (78)一、数学问题1.精度计算——大数阶乘语法:int result=factorial(int n);参数:n:n 的阶乘返回值:阶乘结果的位数注意:本程序直接输出n!的结果,需要返回结果请保留long a[] 需要math.h源程序:int factorial(int n){long a[10000];int i,j,l,c,m=0,w;a[0]=1;for(i=1;i<=n;i++){c=0;for(j=0;j<=m;j++){a[j]=a[j]*i+c;c=a[j]/10000;a[j]=a[j]%10000;}if(c>0) {m++;a[m]=c;}}w=m*4+log10(a[m])+1;printf("\n%ld",a[m]);for(i=m-1;i>=0;i--) printf("%4.4ld",a[i]);return w;}我也可以做到..5 / 782.精度计算——乘法(大数乘小数)语法:mult(char c[],char t[],int m);参数:c[]:被乘数,用字符串表示,位数不限t[]:结果,用字符串表示m:乘数,限定10 以内返回值:null注意:需要string.h源程序:void mult(char c[],char t[],int m){int i,l,k,flag,add=0;char s[100];l=strlen(c);for (i=0;i<l;i++)s[l-i-1]=c[i]-'0';for (i=0;i<l;i++){k=s[i]*m+add;if (k>=10) {s[i]=k%10;add=k/10;flag=1;} else{s[i]=k;flag=0;add=0;}}if (flag) {l=i+1;s[i]=add;} else l=i;for (i=0;i<l;i++)t[l-1-i]=s[i]+'0'; t[l]='\0';}3.精度计算——乘法(大数乘大数)语法:mult(char a[],char b[],char s[]);参数:a[]:被乘数,用字符串表示,位数不限b[]:乘数,用字符串表示,位数不限t[]:结果,用字符串表示返回值:null注意:空间复杂度为o(n^2)需要string.h源程序:void mult(char a[],char b[],char s[]){我也可以做到..6 / 78int i,j,k=0,alen,blen,sum=0,res[65][65]={0},flag=0; char result[65];alen=strlen(a);blen=strlen(b);for (i=0;i<alen;i++)for (j=0;j<blen;j++) res[i][j]=(a[i]-'0')*(b[j]-'0');for (i=alen-1;i>=0;i--){for (j=blen-1;j>=0;j--) sum=sum+res[i+blen-j-1][j]; result[k]=sum%10;k=k+1;sum=sum/10;}for (i=blen-2;i>=0;i--){for (j=0;j<=i;j++) sum=sum+res[i-j][j];result[k]=sum%10;k=k+1;sum=sum/10;}if (sum!=0) {result[k]=sum;k=k+1;}for (i=0;i<k;i++) result[i]+='0';for (i=k-1;i>=0;i--) s[i]=result[k-1-i];s[k]='\0';while(1){if (strlen(s)!=strlen(a)&&s[0]=='0')strcpy(s,s+1);elsebreak;}}4.精度计算——加法语法:add(char a[],char b[],char s[]);参数:a[]:被加数,用字符串表示,位数不限b[]:加数,用字符串表示,位数不限s[]:结果,用字符串表示返回值:null注意:空间复杂度为o(n^2)我也可以做到..7 / 78需要string.h源程序:void add(char a[],char b[],char back[]){int i,j,k,up,x,y,z,l;char *c;if (strlen(a)>strlen(b)) l=strlen(a)+2; else l=strlen(b)+2; c=(char *) malloc(l*sizeof(char));i=strlen(a)-1;j=strlen(b)-1;k=0;up=0;while(i>=0||j>=0){if(i<0) x='0'; else x=a[i];if(j<0) y='0'; else y=b[j];z=x-'0'+y-'0';if(up) z+=1;if(z>9) {up=1;z%=10;} else up=0;c[k++]=z+'0';i--;j--;}if(up) c[k++]='1';i=0;c[k]='\0';for(k-=1;k>=0;k--)back[i++]=c[k];back[i]='\0';}5.精度计算——减法语法:sub(char s1[],char s2[],char t[]);参数:s1[]:被减数,用字符串表示,位数不限s2[]:减数,用字符串表示,位数不限t[]:结果,用字符串表示返回值:null注意:默认s1>=s2,程序未处理负数情况需要string.h源程序:void sub(char s1[],char s2[],char t[])我也可以做到..8 / 78{int i,l2,l1,k;l2=strlen(s2);l1=strlen(s1);t[l1]='\0';l1--;for (i=l2-1;i>=0;i--,l1--){if (s1[l1]-s2[i]>=0)t[l1]=s1[l1]-s2[i]+'0';else{t[l1]=10+s1[l1]-s2[i]+'0';s1[l1-1]=s1[l1-1]-1;}}k=l1;while(s1[k]<0) {s1[k]+=10;s1[k-1]-=1;k--;}while(l1>=0) {t[l1]=s1[l1];l1--;}loop:if (t[0]=='0') {l1=strlen(s1);for (i=0;i<l1-1;i++) t[i]=t[i+1];t[l1-1]='\0';goto loop;}if (strlen(t)==0) {t[0]='0';t[1]='\0';}}6.任意进制转换语法:conversion(char s1[],char s2[],char t[]);参数:s[]:转换前的数字s2[]:转换后的数字d1:原进制数d2:需要转换到的进制数返回值:null注意:高于9 的位数用大写'A'~'Z'表示,2~16 位进制通过验证源程序:void conversion(char s[],char s2[],long d1,long d2){我也可以做到..9 / 78long i,j,t,num;char c;num=0;for (i=0;s[i]!='\0';i++){if (s[i]<='9'&&s[i]>='0') t=s[i]-'0'; else t=s[i]-'A'+10;num=num*d1+t;}i=0;while(1){t=num%d2;if (t<=9) s2[i]=t+'0'; else s2[i]=t+'A'-10;num/=d2;if (num==0) break;i++;}for (j=0;j<i/2;j++){c=s2[j];s2[j]=s[i-j];s2[i-j]=c;}s2[i+1]='\0';}7.最大公约数、最小公倍数语法:resulet=hcf(int a,int b)、result=lcd(int a,int b)参数:a:int a,求最大公约数或最小公倍数b:int b,求最大公约数或最小公倍数返回值:返回最大公约数(hcf)或最小公倍数(lcd)注意:lcd 需要连同hcf 使用源程序:int hcf(int a,int b){int r=0;while(b!=0){r=a%b;a=b;b=r;}return(a);我也可以做到..10 / 78}lcd(int u,int v,int h){return(u*v/h);}8.组合序列语法:m_of_n(int m, int n1, int m1, int* a, int head)参数:m:组合数C 的上参数n1:组合数C 的下参数m1:组合数C 的上参数,递归之用*a:1~n 的整数序列数组head:头指针返回值:null注意:*a 需要自行产生初始调用时,m=m1、head=0调用例子:求C(m,n)序列:m_of_n(m,n,m,a,0);源程序:void m_of_n(int m, int n1, int m1, int* a, int head){int i,t;if(m1<0 || m1>n1) return;if(m1==n1){return;}m_of_n(m,n1-1,m1,a,head); // 递归调用t=a[head];a[head]=a[n1-1+head];a[n1-1+head]=t;m_of_n(m,n1-1,m1-1,a,head+1); // 再次递归调用t=a[head];a[head]=a[n1-1+head];a[n1-1+head]=t;}9.快速傅立叶变换(FFT)语法:kkfft(double pr[],double pi[],int n,int k,double fr[],double fi[],intl,int il);参数:我也可以做到..11 / 78pr[n]:输入的实部pi[n]:数入的虚部n,k:满足n=2^kfr[n]:输出的实部fi[n]:输出的虚部l:逻辑开关,0 FFT,1 ifFTil:逻辑开关,0 输出按实部/虚部;1 输出按模/幅角返回值:null注意:需要math.h源程序:void kkfft(pr,pi,n,k,fr,fi,l,il)int n,k,l,il;double pr[],pi[],fr[],fi[];{int it,m,is,i,j,nv,l0; double p,q,s,vr,vi,poddr,poddi;for (it=0; it<=n-1; it++){m=it; is=0;for (i=0; i<=k-1; i++){j=m/2; is=2*is+(m-2*j); m=j;}fr[it]=pr[is]; fi[it]=pi[is];}pr[0]=1.0; pi[0]=0.0;p=6.283185306/(1.0*n);pr[1]=cos(p); pi[1]=-sin(p);if (l!=0) pi[1]=-pi[1];for (i=2; i<=n-1; i++){p=pr[i-1]*pr[1];q=pi[i-1]*pi[1];s=(pr[i-1]+pi[i-1])*(pr[1]+pi[1]);pr[i]=p-q; pi[i]=s-p-q;}for (it=0; it<=n-2; it=it+2){vr=fr[it]; vi=fi[it];fr[it]=vr+fr[it+1]; fi[it]=vi+fi[it+1];fr[it+1]=vr-fr[it+1]; fi[it+1]=vi-fi[it+1]; }m=n/2; nv=2;for (l0=k-2; l0>=0; l0--){我也可以做到..12 / 78m=m/2; nv=2*nv;for (it=0; it<=(m-1)*nv; it=it+nv)for (j=0; j<=(nv/2)-1; j++){p=pr[m*j]*fr[it+j+nv/2];q=pi[m*j]*fi[it+j+nv/2];s=pr[m*j]+pi[m*j];s=s*(fr[it+j+nv/2]+fi[it+j+nv/2]); poddr=p-q; poddi=s-p-q;fr[it+j+nv/2]=fr[it+j]-poddr;fi[it+j+nv/2]=fi[it+j]-poddi;fr[it+j]=fr[it+j]+poddr;fi[it+j]=fi[it+j]+poddi;}}if (l!=0)for (i=0; i<=n-1; i++){fr[i]=fr[i]/(1.0*n);fi[i]=fi[i]/(1.0*n);}if (il!=0)for (i=0; i<=n-1; i++){pr[i]=sqrt(fr[i]*fr[i]+fi[i]*fi[i]);if (fabs(fr[i])<0.000001*fabs(fi[i])) {if ((fi[i]*fr[i])>0) pi[i]=90.0;else pi[i]=-90.0;}elsepi[i]=atan(fi[i]/fr[i])*360.0/6.283185306;}return;}10.Ronberg 算法计算积分语法:result=integral(double a,double b);参数:a:积分上限b:积分下限我也可以做到..13 / 78function f:积分函数返回值:f 在(a,b)之间的积分值注意:function f(x)需要自行修改,程序中用的是sina(x)/x 需要math.h默认精度要求是1e-5源程序:double f(double x){return sin(x)/x; //在这里插入被积函数}double integral(double a,double b){double h=b-a;double t1=(1+f(b))*h/2.0;int k=1;double r1,r2,s1,s2,c1,c2,t2;loop:double s=0.0;double x=a+h/2.0;while(x<b){s+=f(x);x+=h;}t2=(t1+h*s)/2.0;s2=t2+(t2-t1)/3.0;if(k==1){k++;h/=2.0;t1=t2;s1=s2;goto loop;}c2=s2+(s2-s1)/15.0;if(k==2){c1=c2;k++;h/=2.0;t1=t2;s1=s2;goto loop;}r2=c2+(c2-c1)/63.0;if(k==3){r1=r2; c1=c2;k++;h/=2.0;t1=t2;s1=s2;我也可以做到..14 / 78goto loop;}while(fabs(1-r1/r2)>1e-5){ r1=r2;c1=c2;k++;h/=2.0;t1=t2;s1=s2;goto loop;}return r2;}11.行列式计算语法:result=js(int s[][],int n)参数:s[][]:行列式存储数组n:行列式维数,递归用返回值:行列式值注意:函数中常数N 为行列式维度,需自行定义源程序:int js(s,n)int s[][N],n;{int z,j,k,r,total=0;int b[N][N];/*b[N][N]用于存放,在矩阵s[N][N]中元素s[0]的余子式*/if(n>2){for(z=0;z<n;z++){for(j=0;j<n-1;j++)for(k=0;k<n-1;k++)if(k>=z) b[j][k]=s[j+1][k+1]; elseb[j][k]=s[j+1][k];if(z%2==0) r=s[0][z]*js(b,n-1); /*递归调用*/else r=(-1)*s[0][z]*js(b,n-1);total=total+r;}}else if(n==2)total=s[0][0]*s[1][1]-s[0][1]*s[1][0];return total;我也可以做到..15 / 78}12.求排列组合数语法:result=P(long n,long m); / result=long C(long n,long m);参数:m:排列组合的上系数n:排列组合的下系数返回值:排列组合数注意:符合数学规则:m<=n源程序:long P(long n,long m){long p=1;while(m!=0){p*=n;n--;m--;}return p;}long C(long n,long m){long i,c=1;i=m;while(i!=0){c*=n;n--;i--;}while(m!=0){c/=m;m--;}return c;}13.求某一天星期几语法:result=weekday(int N,int M,int d)参数:N,M,d:年月日,例如:2003,11,4返回值:0:星期天,1 星期一……注意:需要math.h适用于1582 年10 月15 日之后, 因为罗马教皇格里高利十三世在这一天启用新历法.源程序:我也可以做到..16 / 78int weekday(int N,int M,int d){int m,n,c,y,w;m=(M-2)%12;if (M>=3) n=N;else n=N-1;c=n/100;y=n%100;w=(int)(d+floor(13*m/5)+y+floor(y/4)+floor(c/4)-2*c)%7;while(w<0) w+=7;return w;}14.卡特兰(Catalan) 数列原理令h(1)=1,catalan 数满足递归式:h(n)= h(1)*h(n-1) + h(2)*h(n-2) + ... + h(n-1)h(1) (其中n>=2)该递推关系的解为:h(n)=c(2n-2,n-1)/n (n=1,2,3,...)1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440,9694845, 35357670, 129644790, 477638700, 1767263190, 6564120420,24466267020, 91482563640, 343059613650, 1289904147324, 4861946401452, …1.括号化问题。
ACM常见算法

ACM常见算法ACM算法⼀、数论算法 1.求两数的最⼤公约数 2.求两数的最⼩公倍数 3.素数的求法 A.⼩范围内判断⼀个数是否为质数: B.判断longint范围内的数是否为素数(包含求50000以内的素数表):⼆、图论算法1.最⼩⽣成树A.Prim算法:B.Kruskal算法:(贪⼼) 按权值递增顺序删去图中的边,若不形成回路则将此边加⼊最⼩⽣成树。
2.最短路径 A.标号法求解单源点最短路径: B.Floyed算法求解所有顶点对之间的最短路径: C. Dijkstra 算法:3.计算图的传递闭包4.⽆向图的连通分量 A.深度优先 B 宽度优先(种⼦染⾊法)5.关键路径⼏个定义:顶点1为源点,n为汇点。
a. 顶点事件最早发⽣时间Ve[j], Ve [j] = max{ Ve [j] + w[I,j] },其中Ve (1) = 0; b. 顶点事件最晚发⽣时间 Vl[j], Vl [j] = min{ Vl[j] – w[I,j] },其中 Vl(n) = Ve(n); c. 边活动最早开始时间 Ee[I], 若边I由<j,k>表⽰,则Ee[I] = Ve[j]; d. 边活动最晚开始时间 El[I], 若边I由<j,k>表⽰,则El[I] = Vl[k] – w[j,k]; 若 Ee[j] = El[j] ,则活动j为关键活动,由关键活动组成的路径为关键路径。
求解⽅法: a. 从源点起topsort,判断是否有回路并计算Ve; b. 从汇点起topsort,求Vl; c. 算Ee 和 El;6.拓扑排序找⼊度为0的点,删去与其相连的所有边,不断重复这⼀过程。
例寻找⼀数列,其中任意连续p项之和为正,任意q 项之和为负,若不存在则输出NO.7.回路问题 Euler回路(DFS) 定义:经过图的每条边仅⼀次的回路。
(充要条件:图连同且⽆奇点) Hamilton回路定义:经过图的每个顶点仅⼀次的回路。
acm 常用的数学公式

常用公式 (2)划分问题: (3)Stirling公式 (3)皮克定理 (3)卡特兰数 (4)错排公式 (4)等比数列 (5)等差数列 (5)二次函数 (6)二次方程 (7)约瑟夫环 (7)多边形面积 (7)均值不等式的简介 (8)均值不等式的变形 (8)Lucas 定理 (9)斐波那契数列 (10)欧拉函数 (11)蚂蚁爬绳 (12)(a/b)%m (13)泰勒公式 (13)乘法与因式分解公式 (14)三角不等式 (14)某些数列的前n项和 (15)二项式展开公式 (15)三角函数公式 (16)常用公式划分问题:1、n个点最多把直线分成C(n,0)+C(n,1)份;2、n条直线最多把平面分成C(n,0)+C(n,1)+C(n,2)份;3、n个平面最多把空间分成C(n,0)+C(n,1)+C(n,2)+C(n,3)=(n³+5n+6)/6份;4、n个空间最多把“时空”分成C(n,0)+C(n,1)+C(n,2)+C(n,3)+C(n,4)份. Stirling公式lim(n→∞) √(2πn) * (n/e)^n = n!也就是说当n很大的时候,n!与√(2πn) * (n/e) ^ n的值十分接近这就是Stirling公式.(2πn) ^0.5×n^ n ×e^(-n) =n!;皮克定理一个多边形的顶点如果全是格点,这多边形就叫做格点多边形。
有趣的是,这种格点多边形的面积计算起来很方便,只要数一下图形边线上的点的数目及图内的点的数目,就可用公式算出。
这个公式是皮克(Pick)在1899年给出的,被称为“皮克定理”,这是一个实用而有趣的定理。
给定顶点坐标均是整点(或正方形格点)的简单多边形,皮克定理说明了其面积S和内部格点数目a、边上格点数目b的关系:S=a+ b/2 - 1。
(其中a表示多边形内部的点数,b表示多边形边界上的点数,S表示多边形的面积) 卡特兰数原理:令h(1)=1,h(0)=1,catalan数满足递归式:h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0) (其中n>=2)另类递归式:h(n) = h(n-1)*(4*n-2)/(n+1);该递推关系的解为:h(n)=C(2n,n)/(n+1) (n=1,2,3,...)卡特兰数的应用(实质上都是递归等式的应用)错排公式当n个编号元素放在n个编号位置,元素编号与位置编号各不对应的方法数用M(n)表示,那么M(n-1)就表示n-1个编号元素放在n-1个编号位置,各不对应的方法数,其它类推.第一步,把第n个元素放在一个位置,比如位置k,一共有n-1种方法;第二步,放编号为k的元素,这时有两种情况.1,把它放到位置n,那么,对于剩下的n -2个元素,就有M(n-2)种方法;2,不把它放到位置n,这时,对于这n-1个元素,有M(n-1)种方法;综上得到递推公式:M(n)=(n-1)[M(n-2)+M(n-1)] 特殊地,M(1)=0,M(2)=1通项公式:M(n)=n![(-1)^2/2!+…+(-1)^(n-1)/(n-1)!+(-1)^n/n!]优美的式子:Dn=[n!/e+0.5],[x]为取整函数.公式证明较简单.观察一般书上的公式,可以发现e-1的前项与之相同,然后作比较可得/Dn-n!e-1/<1/(n+1)<0.5,于是就得到这个简单而优美的公式(此仅供参考)等比数列(1) 等比数列:a (n+1)/an=q (n∈N)。
ACM算法竞赛模板个人总结汇总

数学 (4)最大公约数、最小公倍数 (4)最大公约数——欧几里得算法O(n) (4)Stein算法O( log(max(a,b)) ) (4)最小公倍数: (4)素数相关 (5)普通素数判断 (5)筛法求素数[1,N] (5)二次筛法求素数[L,R] (6)Miller-Rabbin素数测试方法 (7)算术基本定理的定义和性质: (8)同余方程[组] 乘法模逆元中国剩余定理 (9)扩展欧几里得,求一组解x,y,使得gcd(a,b) = d = a * x + b * y (9)扩展欧几里得,求所有解x,y,使得c = a * x + b * y (10)扩展欧几里得,求a关于n的逆元a^-1,使得a * a^-1 ≡ 1(mod n) (10)扩展欧几里得,求解x,满足同余方程组x ≡ Ri(mod Ai) (10)扩展欧几里得,求解x,满足高次同余方程A^x ≡ B(mod C) (11)中国剩余定理: (13)中国剩余定理最小非负数解的算法: (14)求解a*x + b*y = c的其中一组解,使得|x| + |y|尽可能小,若相等,则a|x| + b|y|尽可能小。
(15)整数快速幂 (16)矩阵快速幂 (16)整数分解 (18)试除法整数分解 (18)筛法整数分解 (18)PollardRho大整数分解 (19)欧拉函数 (22)直接欧拉函数 (22)递推快速求欧拉函数 (23)容斥原理 (23)母函数 (24)普通母函数 (24)指数型母函数 (25)其他相关 (27)九余数定理:一个数N各位数字的和,对9取余等于这个数对9取余 (27)给你一个奇数N,求1~N的奇数平方和: S = N*(N+1)*(N+2)/6 (27)约瑟夫问题:有N个人,编号为1~N,按顺时针围成一个圈,每数k个人,就将这个人从圈中消除,问:最终只留下一个人的编号。
(27)给你整数x和y的和以及x和y的积,是否能找到满足这两个式子的整数x和整数y。
简单数论

例题二:poj1061青蛙的约会
简单解题思路: 设s步之后相遇,此式走了k圈 (x+m*s)-(y+n*s)=k*l(k=0,1,2....) 稍微变一下形得: (n-m)*s+k*l=x-y 令n-m=a,k=b,x-y=c,即 a*s +b*l=c 只要上式存在整数解,则两青蛙能相遇,否则不能 求其整数解
求解单个n的phi(n)时,用试除法找出所有的质因数,然后再利用公式可以求解 求解1-n的欧拉函数表时用类似筛法的方法
例题一:Uva 11426
题目大意:
输入正整数n,
求:gcd(1,2)+gcd(1,3)+……+gcd(n-1,n), 满足所有1<=i<j<=n的gcd(i,j)的和 输入格式: 不超过100组数据,2<=n<=4 000 000
由于本人的关系下面一部分还未深入学习, 自己可以去深入学习,共同探讨
1.欧拉方程
2.素数测试
3.大数分解质因数
谢
谢
4.模线性方程
扩展欧几里德算法:
EXTENDED-EUCLID(a, b) if b = 0 then return (a, 1, 0) (d’,x’,y’) ← EXTENDED-EUCLID(b, a%b) (d, x, y) ← (d’, y’, x’ – (a/b) * y’) return (d, x, y)
x a j M j M j (mod m )满足方程 (1).
j 1
k
6.唯一因子分解
唯一质因子分解定理:合数a仅能以一种方式,写成如下的乘 积形式: a=p1e1p2e2…prer 其中pi为素数,p1<p2<…<pr,且ei为正整数。 因子分解没有很好地算法,一般为用小于n的素数去试除,算 法的优化体现在寻找素数上,而非试除过程
acm数学公式

锥体体积公式 V=1/3*S*H
圆锥体体积公式 V=1/3*pi*r2h
柱体体积公式 斜棱柱体积
V=s*h
圆柱体
V=pi*r2h
V=S'L 长)
(S'是直截面面积,L 是侧棱
注:pi=acos(-1.0);
2
划分问题:
1、n 个点最多把直线分成 C(n,0)+C(n,1)份; 2、n 条直线最多把平面分成 C(n,0)+C(n,1)+C(n,2)份; 3、n 个平面最多把空间分成 C(n,0)+C(n,1)+C(n,2)+C(n,3)=(n³+5n+6)/6 份; 4、n 个空间最多把“时空”分成 C(n,0)+C(n,1)+C(n,2)+C(n,3)+C(n,4)份.
1
常用公式
|a+b|≤|a|+|b|
|a-b|≤|a|+|b| |a|≤b<=>-b≤a≤b
三角不等式
|a-b|≥|a|-|b|
一元二次方 程的解
-b+√(b2-4ac)/2a
根与系数的关系
X1+X2=-b/a
-|a|≤a≤|a| -b-√(b2-4ac)/2a
X1*X2=c/a
注:韦达定理
1+2+3+4+5+6+7+8+9+…+n=n(n+1)/2
常用数学公式表:解析几何公式
圆的标准方程 (x-a)2+(y-b)2=r2
注:(a,b)是圆心坐标
圆的一般方程 x2+y2+Dx+Ey+F=0
关于欧拉函数的等式

关于欧拉函数的等式
我们要证明关于欧拉函数的等式。
欧拉函数通常表示为φ(n),它表示小于n 且与n互质的正整数的个数。
我们要证明的等式是:
φ(mn) = φ(m)φ(n) 当 gcd(m, n) = 1
其中,gcd(m, n)表示m和n的最大公约数。
假设 m 和 n 是两个互质的正整数。
根据欧拉函数的定义,我们可以得到以下结论:
1. φ(m) 表示小于 m 且与 m 互质的正整数的个数。
2. φ(n) 表示小于 n 且与 n 互质的正整数的个数。
3. 当 m 和 n 互质时,小于 mn 且与 mn 互质的正整数可以分解为小于 m 且与 m 互质的正整数与小于 n 且与 n 互质的正整数的乘积。
因此,我们可以得到以下数学表达式:
φ(mn) = φ(m)φ(n) 当 gcd(m, n) = 1
m 和 n 不互质,无法验证等式。
ACM数论

4
Eratosthenes筛法
2)给定一个范围(求这个范围内的素 数),进行如下步骤: 0.从2开始,2是第一个素数。也是第一 个新素数。取出2。 1.筛掉所有新素数的倍数。 2.留下来的数里面第一个(最小的)是 新素数。取出这个新素数。 3.重复1和2直到没有数存在。
17
扩展欧几里德算法:
EXTENDED-EUCLID(a, b) if b = 0 then return (a, 1, 0) (d’,x’,y’) ← EXTENDEDEUCLID(b, a%b) (d, x, y) ← (d’, y’, x’ – (a/b) * y’) return (d, x, y)
41
元素的幂
3k mod 7为:
i 0 1 2 3 4 5 6 7 8 9 10 11 3k mod 7 1 3 2 6 4 5 1 3 2 6 4 5 i 0 1 2 3 4 5 6 7 8 9 10 11 2k mod 7 1 2 4 1 2 4 1 2 4 1 2 4
需要保存p112个二元组生成这些二元组需要的时间为op112对二元组进行排序需要的时间为ologp112p112第5步的循环最多执行p112次每次如果采用二分查找来寻找指定元素那么总的时间复杂度为op112logp11239离散对数例
ACM 数论 zzsycqs@
1
初等数论的概念
整除性和约数: 假设d和a是整数,d|a(读作d整除a), 意味着存在某个整数k,有a=kd。 如果d|a,并且d≥0,则称d是a的约数。 每个整数a都可以被其平凡约数1和a整除, a的非平凡约数也称为a的因子。