{"id":13672354,"url":"https://github.com/songtianyi/acmer-qualification-code","last_synced_at":"2026-01-16T22:51:16.050Z","repository":{"id":45751979,"uuid":"133674308","full_name":"songtianyi/acmer-qualification-code","owner":"songtianyi","description":"ACMer 入门级算法模板","archived":false,"fork":false,"pushed_at":"2022-08-01T02:09:50.000Z","size":779,"stargazers_count":217,"open_issues_count":0,"forks_count":35,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-11-11T10:42:24.273Z","etag":null,"topics":["acm","acm-icpc","algorithm","c","codeforces","data-structures","leetcode","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/songtianyi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":null,"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":["https://songtianyi.info/pages/life/sponsors.html"]}},"created_at":"2018-05-16T14:00:30.000Z","updated_at":"2024-04-24T15:51:28.000Z","dependencies_parsed_at":"2022-09-13T17:11:11.424Z","dependency_job_id":null,"html_url":"https://github.com/songtianyi/acmer-qualification-code","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/songtianyi%2Facmer-qualification-code","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/songtianyi%2Facmer-qualification-code/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/songtianyi%2Facmer-qualification-code/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/songtianyi%2Facmer-qualification-code/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/songtianyi","download_url":"https://codeload.github.com/songtianyi/acmer-qualification-code/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251212712,"owners_count":21553508,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["acm","acm-icpc","algorithm","c","codeforces","data-structures","leetcode","rust"],"created_at":"2024-08-02T09:01:33.261Z","updated_at":"2026-01-16T22:51:16.008Z","avatar_url":"https://github.com/songtianyi.png","language":"Rust","funding_links":["https://songtianyi.info/pages/life/sponsors.html"],"categories":["Rust"],"sub_categories":[],"readme":"# acmer-qualification-code\n\n### Programming Contest Archive\n\nSome coding contest solutions are achieved and grouping by hosted platform like [*Codeforces*](https://codeforces.com/).\n\n| :warning: Caution |\n|:---------------------------|\n| Unaccepted answers are included, be carefull :exclamation::exclamation::exclamation:|\n\n```shell\n# find solutions in Rust\nfind . -name \"*.rs\"\n# find solutions in C\nfind . -name \"*.c\"\n```\n\n### Handy templates in Rust\n\n```rust\n#[allow(unused_imports)]\nuse std::cmp::max;\n#[allow(unused_imports)]\nuse std::cmp::min;\n#[allow(unused_imports)]\nuse std::collections::HashMap;\n#[allow(unused_imports)]\nuse std::collections::HashSet;\nuse std::io;\n\n// input macros\n#[allow(unused_macros)]\n\n// rustc +nightly -Zunpretty=expanded your.rs\nmacro_rules! read {\n    // eg.\n    // let s = read!();\n    () =\u003e {{\n        let mut line: String = String::new();\n        io::stdin().read_line(\u0026mut line).unwrap();\n        line.trim().to_string()\n    }};\n\n    // eg.\n    // let v = read!(Vec\u003ci32\u003e)\n    // let v = read!(Vec\u003cchar\u003e)\n    (Vec\u003c$t:ty\u003e) =\u003e ({\n        let mut line: String = String::new();\n        io::stdin().read_line(\u0026mut line).unwrap();\n        line.split_whitespace()\n            .map(|x| x.parse::\u003c$t\u003e().unwrap())\n            .collect()\n    });\n\n    // eg.\n    // let v = read!(i32);\n    // let v = read!(i64);\n    // let (i, j, k) = read!(i32, i32, i32);\n    ($($t:ty),*) =\u003e {{\n        let mut line = String::new();\n        io::stdin().read_line(\u0026mut line).unwrap();\n        let mut iter = line.split_whitespace();\n        ($(iter.next().unwrap().parse::\u003c$t\u003e().unwrap()),*)\n    }};\n}\n\nfn solve() {\n}\n\nfn main() {\n    let mut t = read!(i32);\n    while t \u003e 0 {\n        t -= 1;\n        solve();\n        print!(\"\\n\");\n    }\n}\n```\n\n### Handy templates in C\n\n#### 1. printf\n\n###### 1.1 符号说明\n\n```pla\n      %a(%A)     浮点数、十六进制数字和p-(P-)记数法(C99)\n      %c         字符\n      %d         有符号十进制整数\n      %f         浮点数(包括float和double)\n      %e(%E)     浮点数指数输出[e-(E-)记数法]\n      %g(%G)     浮点数不显无意义的零\"0\"\n      %i         有符号十进制整数(与%d相同)\n      %u         无符号十进制整数\n      %o         八进制整数    e.g.     0123\n      %x(%X)     十六进制整数0f(0F)   e.g.   0x1234\n      %p         指针\n      %s         字符串\n      %%         \"%\"\n```\n\n###### 1.2 对齐\n\n```\n\n      左对齐：\"-\"   e.g.   \"%-20s\"\n      右对齐：\"+\"   e.g.   \"%+20s\"\n      空格：若符号为正，则显示空格，负则显示\"-\"   e.g.   \"%  6.2f\"      \n      #：对c,s,d,u类无影响；对o类，在输出时加前缀o；对x类，在输出时加前缀0x；对e,g,f 类当结果有小数时才给出小数点\n```\n\n###### 1.3 格式化输出\n\n```\n\n ［标志］［输出最少宽度］［．精度］［长度］类型\n  \"％-md\" ：左对齐，若m比实际少时，按实际输出。\n  \"%m.ns\"：输出m位，取字符串(左起)n位，左补空格，当n\u003em or m省略时m=n.\n  \t\t\t\t\t\te.g. \"%7.2s\"\t输入CHINA\n                                 　     输出\"     CH\"\n  \"%m.nf\"：输出浮点数，m为宽度，n为小数点右边数位\n           \t\t\t\te.g. \"%3.1f\"   输入3852.99\n                                       输出3853.0\n```\n\n#### 2. 符号的英文读法\n\n```\n\n+　 plus　加号；正号\n-　 minus　减号；负号\n±　plus or minus　正负号\n×　is multiplied by　乘号\n÷　is divided by　除号\n＝　is equal to　等于号\n≠　is not equal to　不等于号\n≡　is equivalent to　全等于号\n≌　is equal to or approximately equal to　等于或约等于号\n≈　is approximately equal to　约等于号\n＜　 is less than　小于号\n＞　is greater than　大于号\n≮　is not less than　不小于号\n≯ 　is not more than　不大于号\n≤　is less than or equal to　小于或等于号\n≥　is more than or equal to　大于或等于号\n%　 per cent　百分之…\n‰　per mill　千分之…\n∞　 infinity　无限大号\n∝　varies as　与…成比例\n√　(square) root　平方根\n∵　since; because　因为\n∴　hence　所以\n∷　equals, as (proportion)　等于，成比例\n∠　angle　 角\n⌒　semicircle　半圆\n⊙　circle　圆\n○　circumference　圆周\nπ　pi 圆周率\n△ 　triangle　三角形\n⊥　perpendicular to　垂直于\n∪　union of　并，合集\n∩　 intersection of 交，通集\n∫　the integral of …的积分\n∑　(sigma) summation of　总和\n°　degree　度\n′　minute　分\n″　second　秒\n℃　Celsius system　摄氏度\n{ 　open brace, open curly　左花括号\n}　close brace, close curly　右花括号\n(　 open parenthesis, open paren　左圆括号\n)　close parenthesis, close paren　右圆括号\n() brakets/ parentheses　括号\n[　open bracket 左方括号\n]　 close bracket 右方括号\n[] square brackets　方括号\n.　period, dot　句号，点\n|　 vertical bar, vertical virgule　竖线\n\u0026　ampersand, and, reference, ref　和，引用\n*　asterisk, multiply, star, pointer　星号，乘号，星，指针\n/　slash, divide, oblique 斜线，斜杠，除号\n//　slash-slash, comment 双斜线，注释符\n#　pound　井 号\n\\　backslash, sometimes escape　反斜线转义符，有时表示转义符或续行符\n~　tilde　波浪符\n. 　full stop　句号\n,　comma　逗号\n:　colon　冒号\n;　semicolon　分号\n?　 question mark　问号\n!　exclamation mark (英式英语) exclamation point (美式英语)\n‘ 　apostrophe　撇号\n-　hyphen　连字号\n– dash 破折号\n…　dots/ ellipsis　省略号\n\" 　single quotation marks 单引号\n\"\"　double quotation marks 双引号\n‖ parallel 双线号\n\u0026　ampersand = and\n～　swung dash 代字号\n§　section; division 分节号\n→　arrow 箭号；参见号\n```\n\n#### 3. C/C++头文件\n\n```c++\n///C\n#include \u003cassert.h\u003e         //断言\n#include \u003cctype.h\u003e          //字符处理\n#include \u003cerrno.h\u003e          //定义错误码\n#include \u003cfloat.h\u003e          //浮点数处理\n#include \u003climits.h\u003e         //定义各种数据类型最值常量\n#include \u003clocale.h\u003e         //定义本地化函数\n#include \u003cmath.h\u003e           //定义数学函数\n#include \u003csetjmp.h\u003e         //非局部跳转\n#include \u003csignal.h\u003e         //信号处理\n#include \u003cstdarg.h\u003e         //变长变元表\n#include \u003cstddef.h\u003e\n#include \u003cstdio.h\u003e          //定义输入／输出函数\n#include \u003cstdlib.h\u003e         //定义杂项函数及内存分配函数\n#include \u003cstring.h\u003e         //字符串处理\n#include \u003ctime.h\u003e           //定义关于时间的函数\n\n///////////////////////////////////////////////////////////////////////////////\n///标准 C++\n///C语言部分略\n#include \u003calgorithm\u003e        //STL 通用算法\n#include \u003cbitset\u003e           //STL 位集容器\n#include \u003ccomplex\u003e          //复数类\n#include \u003cdeque\u003e            //STL 双端队列容器\n#include \u003cexception\u003e        //异常处理类\n#include \u003cfstream\u003e          //文件输入/输出\n#include \u003cfunctional\u003e       //STL 定义运算函数（代替运算符）\n#include \u003climits\u003e\n#include \u003clist\u003e             //STL 线性列表容器\n#include \u003cmap\u003e              //STL 映射容器\n#include \u003ciomanip\u003e\n#include \u003cios\u003e              //基本输入／输出支持\n#include \u003ciosfwd\u003e           //输入／输出系统使用的前置声明\n#include \u003ciostream\u003e\n#include \u003cistream\u003e          //基本输入流\n#include \u003costream\u003e          //基本输出流\n#include \u003cqueue\u003e            //STL 队列容器\n#include \u003cset\u003e              //STL 集合容器\n#include \u003csstream\u003e          //基于字符串的流\n#include \u003cstack\u003e            //STL 堆栈容器　　　　\n#include \u003cstdexcept\u003e        //标准异常类\n#include \u003cstreambuf\u003e        //底层输入／输出支持\n#include \u003cstring\u003e           //字符串类\n#include \u003cutility\u003e          //STL 通用模板类\n#include \u003cvector\u003e           //STL 动态数组容器\n#include \u003ccwchar\u003e\n#include \u003ccwctype\u003e\nusing namespace std; \n\n///////////////////////////////////////////////////////////////////////\n///C99 增加\n#include \u003ccomplex.h\u003e        //复数处理\n#include \u003cfenv.h\u003e           //浮点环境\n#include \u003cinttypes.h\u003e       //整数格式转换\n#include \u003cstdbool.h\u003e        //布尔环境\n#include \u003cstdint.h\u003e         //整型环境\n#include \u003ctgmath.h\u003e         //通用类型数学宏\n///////////////////////////////////////////////////////////////////////\n\n```\n\n#### 4. 注意事项\n\n* 变量名count会和\\\u003calgorithm\u003e中的count冲突\n* cin和scanf不能同时使用，cout和printf不能同时使用\n* GCC/G++中，输出double应该使用printf(\"%f\") 而不是lf\n* 如果用scanf接收了一行数据，再用gets, gets会直接接收到空串！因为，scanf接受了一行数据以后换行符仍然在缓冲区中，gets()遇到换行符，接收会结束. 解决方法，scanf 后加一个getchar()\n* 精度问题\n* 2^31-1 =0x7fffffff\n* -2^31 =-0x7fffffff-1\n* 精确的pi :double pi=acos(-1);\n\n#### 5. N次方求和\n\n![img](https://acmer.oss-cn-beijing.aliyuncs.com/1526545956817.jpg)\n\n![img](https://acmer.oss-cn-beijing.aliyuncs.com/1526546055667.jpg)\n\n#### 6.  字符串处理\n\n```c\n/**\n *颠倒一个字符串的顺序 \"abc\\0\" – \"cba\\0\"\n *array\t为需要颠倒顺序的字符串\n *length 为字符串array的长度\n */\nint stringReverse(char *array,int length){\n    int i = 0,j = length - 1;\n    while(i \u003c j){\n        char cha = array[i];\n        array[i] = array[j];\n        array[j] = cha;i++;j--;\n    }\n    return 1;\n}\n```\n\n```c\n// 颠倒一个字符串部分位置的顺序, 原地\ninline void swap(char *x, char *y) {\n    char t = *x; *x = *y; *y = t;\n}\n \nchar* reverse(char *buffer, int i, int j)\n{\n    while (i \u003c j)\n        swap(\u0026buffer[i++], \u0026buffer[j--]);\n \n    return buffer;\n}\n```\n\n```c\n// 反转整数\n#include\u003cstdio.h\u003e\n#include\u003cstdlib.h\u003e\n#define INF_MAX 0x7fffffff\n#define INF_MIN -0x7fffffff-1\nint reverse(int x){\n    int ans = 0;\n    int l = x;\n    while(l != 0 ) {\n        int h = l%10;\n        l = l/10;\n        // ans * 10 + h \u003e INF_MAX\n        // ans * 10 + h \u003c INF_MIN\n        if(INF_MAX/10 \u003c ans || (INF_MAX/10 == ans \u0026\u0026 h \u003e 7)) {\n            return 0;\n        }else if(INF_MIN/10 \u003e ans || (INF_MIN/10 == ans \u0026\u0026 h \u003c -8)) {\n            return 0;\n        }\n        ans = ans * 10 + h;\n    }\n    return ans;\n}\n\nint main() {\n    printf(\"%d\\n\", reverse(123));\n    printf(\"%d\\n\", reverse(-123));\n    return 0;\n}\n```\n\n```c\n// 最长回文子串, 暴力解法\n// 给定一个字符串 s，找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。\n// \n// 示例 1：\n// \n// 输入: \"babad\"\n// 输出: \"bab\"\n// 注意: \"aba\" 也是一个有效答案。\n// 示例 2：\n// \n// 输入: \"cbbd\"\n// 输出: \"bb\"\n\n#include\u003cstdio.h\u003e\n#include\u003cstdlib.h\u003e\n#include\u003cstring.h\u003e\n\nint valid(char *s, int i, int j) {\n    while(i \u003c= j) {\n        if(s[i++] != s[j--]) {\n            return 0;\n        }\n    }\n    return 1;\n}\nchar * longestPalindrome(char * s){\n    int len = strlen(s);\n    if (len == 1) {\n        return s;\n    }\n    int  max = 1, maxi = 0;\n    for(int i = 0;i \u003c len-1;i++) {\n        for(int j = i+1;j \u003c len;j++) {\n            int x = j - i + 1;\n            if(x \u003e max \u0026\u0026 valid(s, i,j)) {\n                if(x  \u003e max) {\n                    max = x;\n                    maxi = i;\n                }\n            }\n        }\n    }\n    s = s+maxi;\n    s[max] = '\\0';\n    return s;\n}\n\nint main() {\n    char a[10] = \"babad\";\n    printf(\"%s\\n\", longestPalindrome(a));\n    return 0;\n}\n```\n\n#### 7. 进制转换\n\n```c\n/**\n *将任意进制数转换成整型范围内的十进制数\n *str   为base进制数\n *base  为str的进制\n *length为str的长度\n */\nint myPow(int a,int b){\n    int rs = 1;\n    while(b--){rs *= a;}\n    return rs;\n}\nint anyToDecimal(char *str,int base,int length){\n\tint decimal = 0,i;\n\tfor(i = 0;i \u003c length;i++){\n\t\tif(str[i] \u003e= 65)/*为十六进制的时候*/{\n\t\t\tdecimal += myPow(base,length-1 - i)*(str[i] - 'A' + 10);\n\t\t}\n\t\telse if(str[i] \u003c= '9'){\n\t\t\tdecimal += myPow(base,length-1 - i)*(str[i] - '0');\n\t\t}\n\t}\n\treturn decimal;\n}\n```\n\n#### 8. 栈\n\n```c++\n/**\n *栈 C++\n *clear() push() top() empty() pop() size()\n *free()\n */\ntypedef int T; \nstruct myStack{\n\n    int curr,size_limit;\n    T *array;\n    myStack(int s){//必须传入栈的大小\n        curr = -1; size_limit = s;\n        array = new T[s];\n    }\n    void clear(){curr = -1;}/*清空栈 重新使用*/\n    void free(){delete array;clear();}/*释放栈 不能再使用*/\n    T top(){\n        if(curr \u003e -1){return array[curr];}\n        else return curr;}\n    bool push(T v){\n        if(curr+1 \u003c size_limit){array[++curr] = v;return true;}\n        return false;}\n    bool empty(){\n        if(curr \u003c 0)return true;\n        else return false;}\n    void pop(){curr--;}\n    int  size(){return curr+1;}\n\n}; \n\n```\n\n``` c\n// c stack 没有安全检查, 使用时自己注意\n#include \u003cstdio.h\u003e\n#include \u003cstdlib.h\u003e\n\ntypedef int T;\nstruct stack {\n  T *values;\n  int pos, size;\n};\n\nvoid init_stack(struct stack *s, int size) {\n  s-\u003epos = 0;\n  s-\u003esize = size;\n  s-\u003evalues = malloc(sizeof(T) * size);\n}\n\nstruct stack *create(int size) {\n  struct stack *p = malloc(sizeof(struct stack));\n  init_stack(p, size);\n  return p;\n}\nvoid delete (struct stack *s) { free(s-\u003evalues); }\n\n// not safe\nvoid push(struct stack *s, T v) { s-\u003evalues[s-\u003epos++] = v; }\nvoid dump(struct stack *s) {\n  printf(\"[%p\", s-\u003evalues[0]);\n  int i = 1;\n  while(i \u003c s-\u003epos) {\n     printf(\", %p\", s-\u003evalues[i++]); \n  }\n  printf(\"]\\n\");\n}\nint empty(struct stack *s) { return s-\u003epos == 0; }\nint full(struct stack *s) { return s-\u003epos \u003e= s-\u003esize; }\nstruct T *pop(struct stack *s) { return s-\u003evalues[--s-\u003epos]; }\nstruct T *top(struct stack *s) { return s-\u003evalues[s-\u003epos - 1]; }\n\nint main() {\n  struct stack *s = create(10);\n  push(s, 1);\n  dump(s);\n  delete (s);\n}\n\n```\n\n#### 8. 表达式转换\n\n```c++\n/**\n*自己定义操作符的优先级\n*/\nint priorityLevel(const char x){\n}\n/**\n*自己定义操作符的结合性，左或者右\n*/\nint rightAssociative(const char x){\n\n    switch(x){\n        case '^':{ return 1;}\n    }\n    return 0;\n\n}\t\n/**\n*shunting_yard: infix expression to RPN\n*中缀转换成后缀\n*传入中缀表达式expression，RPN保存在result中\n*/\nvoid shunting_yard(char *result, const char *expression){\n\n    stack\u003cchar\u003e my;\n    int len = strlen(expression), r = 0;\n    for(int  i = 0;i \u003c len;i++){\n        if(expression[i] == ' ') continue;\n        if(expression[i] \u003e= '0' \u0026\u0026 expression[i] \u003c= '9'){\n            //是数字直接加到输出队列\n            result[r++] = expression[i];\n        }\n        else{//操作符或者括号\n            ///以下代码需要根据具体情况修改\n            ///需要注意操作符的优先级和结合性\n            if(r != 0 \u0026\u0026 result[r-1] != ' ') result[r++] = ' ';//数字之间必须要用空格隔开\n            if(expression[i] == ')'){\n                while(!my.empty() \u0026\u0026 my.top() != '('){\n                    //遇到右括号的时候 要将括号里边的表达式看成一个整体\n                    //将左括号之后的内容都弹出\n                    result[r++] = my.top(); my.pop();\n                }\n                if(!my.empty()) my.pop();//弹出左括号\n            }\n            else{\n                while(expression[i] != '('//左括号直接入栈\n                    \u0026\u0026!my.empty()//栈为空的时候也直接入栈\n                    ///如果是操作符 需要弹出栈里优先级比它高 或者 优先级相等但是是左结合的操作符\n                    \u0026\u0026 my.top() != '('//遇到左括号相当于栈为空\n                    \u0026\u0026 (\n                        (priorityLevel(my.top()) \u003e priorityLevle(expression[i]))\n                  ||(priorityLevel(my.top())==priorityLevle(expression[i])\u0026\u0026 !rightAssociative(my.top()))\n                       )\n                    ){\n                    result[r++] = my.top(); my.pop();\n                }\n                my.push(expression[i]);//将这个操作符入栈\n            }\n        }\n    }\n    while(!my.empty()){\n        result[r++] = my.top(); my.pop();\n    }\n    result[r] = '\\0';\n\n}\n\n```\n\n#### 9. 搜索\n\n``` c\n/**\n *二分查找\n *如果找到flag为1 posi为所查找到的位置\n *如果没找到flag为0 posi为该值应该插入的位置\n *传入的区间为[left,right)\n */\n\nstruct node{\n    int flag;//0表示不存在\n    int posi;//返回插入或者删除的位置\n};\nstruct node *binarySearch(int *array,int value,int left,int right){\n    struct node *pointer = (struct node*)malloc(sizeof(struct node));\n    pointer-\u003eflag = 0;pointer-\u003eposi = -1;\n    if(right == 0){//left == -1 impossible\n        pointer-\u003eflag = pointer-\u003eposi = 0;\n        return pointer;\n    }\n    while(left \u003c= right){\n        int mid = ((left + right) \u003e\u003e 1);\n        if(value == array[mid]){\n            pointer-\u003eflag = 1;\n            pointer-\u003eposi = mid;\n            return pointer;\n        }\n        else{\n\t\t\t(value \u003e array[mid])?(left=mid+1):(right=mid-1);\n\t\t}\n\t}\n\tpointer-\u003eposi = left;return pointer;\n}\n```\n\n#### 10. 排序\n\n```c\n/**\n * 二叉排序树模板\n * 插入函数 插入之前应先申请一个要插入的p节点 然后传进去\n * 查找函数 root为根节点 parent等于root value为要查找的值\n * ret_flag为0返回查找到的节点的父节点这样便于删除时使用  ret_flag\n * 为1返回查找到的节点的指针\n * 删除函数 传入要删除的节点的父节点和要删除的节点\n * 如果待删节点为父节点的左孩子is_left=1 如果为右孩子 is_left=1 构造函数\n * 将一个数组从start到end（不包括end）的范围构造为一个二叉排序树 root为根节点\n */\n#include \u003cstdio.h\u003e\n#include \u003cstdlib.h\u003e\n\nstruct node {\n  int value;\n  struct node *left, *right;\n};\nstruct node *bst_insert(struct node *curr, struct node *p) {\n  if (curr == NULL) {\n    return p;  //插入的节点的左右孩子的初始值一定要为NULL\n  } else if (p-\u003evalue \u003c curr-\u003evalue) {\n    curr-\u003eleft = bst_insert(curr-\u003eleft, p);\n  } else {\n    curr-\u003eright = bst_insert(curr-\u003eright, p);\n  }\n  return curr;\n}\n\nvoid bst_inorder_traversal(struct node *curr) {\n  if (curr != NULL) {\n    bst_inorder_traversal(curr-\u003eleft);\n    printf(\"(%p, %d)\\n\", curr, curr-\u003evalue);\n    bst_inorder_traversal(curr-\u003eright);\n  }\n}\n\nvoid bst_preorder_traversal(struct node *curr) {\n  if (curr != NULL) {\n    printf(\"(%p, %d)\\n\", curr, curr-\u003evalue);\n    bst_preorder_traversal(curr-\u003eleft);\n    bst_preorder_traversal(curr-\u003eright);\n  }\n}\n\nvoid bst_postorder_traversal(struct node *curr) {\n  if (curr != NULL) {\n    bst_postorder_traversal(curr-\u003eleft);\n    bst_postorder_traversal(curr-\u003eright);\n    printf(\"(%p, %d)\\n\", curr, curr-\u003evalue);\n  }\n}\n\nstruct node *bst_search(struct node *curr, struct node *parent, int value,\n                        int ret_flag) {\n  if (curr == NULL) {\n    // leaf node\n    return NULL;\n  } else if (curr-\u003evalue == value) {\n    // found, check ret flag\n    // 返回的是要查找节点的父节点或者是要查找的节点\n    // 使用父节点是因为这样便于删除的时候使用父节点进行删除\n    if (ret_flag == 0) {\n      return parent;\n    } else {\n      return curr;\n    }\n  } else if (value \u003c curr-\u003evalue) {\n    return bst_search(curr-\u003eleft, curr, value, ret_flag);\n  } else {\n    return bst_search(curr-\u003eright, curr, value, ret_flag);\n  }\n}\n\nint bst_delete(struct node *parent, struct node *p, int is_left) {\n  if (p-\u003eleft == NULL \u0026\u0026 p-\u003eright == NULL) {\n    // leaft node\n    if (is_left) {\n      // p 为parent的左子叶\n      // 将 parent的左指针置为空\n      parent-\u003eleft = NULL;\n    } else {\n      // p 为parent的右子叶\n      parent-\u003eright = NULL;\n    }\n    free(p);\n  } else if (p-\u003eleft == NULL) {\n    // 待删除节点无左子树，说明有右子树\n    if (is_left) {\n      // 将待删除的节点的右子树 赋值给父节点的左子树\n      parent-\u003eleft = p-\u003eright;\n    } else {\n      // 将待删除的节点的右子树 赋值给父节点的左子树\n      parent-\u003eright = p-\u003eright;\n    }\n    free(p);\n  } else if (p-\u003eright == NULL) {\n    // 待删除节点无右子树，说明有左子树\n    if (is_left) {\n      parent-\u003eleft = p-\u003eleft;\n    } else {\n      parent-\u003eright = p-\u003eleft;\n    }\n    free(p);\n  } else {\n    struct node *s = p-\u003eright;\n    struct node *sp = p;\n    //找右子树中最左的节点 或者找左子树中最右的节点\n    //然后和要删除的位置交换value\n    //这里选择前者\n    while (s-\u003eleft != NULL) {\n      sp = s;\n      s = s-\u003eleft;\n    }\n    printf(\"%d --\u003e %d\\n\", p-\u003evalue, s-\u003evalue);\n    p-\u003evalue = s-\u003evalue;\n    if (sp == p) {\n      // p 的右子树没有左子树\n      sp-\u003eright = s-\u003eright;\n    } else {\n      //因为s肯定没有左子树 所以把右子树接在父节点的左指针上就行了\n      sp-\u003eleft = s-\u003eright;\n    }\n    free(s);\n  }\n  return 1;\n}\nvoid bst_build(struct node *root, int *array, int start, int end) {\n  // [start, end)\n  while (start \u003c end) {\n    // create node\n    struct node *p = malloc(sizeof(struct node));\n    p-\u003evalue = array[start];\n    p-\u003eleft = p-\u003eright = NULL;  // init\n    bst_insert(root, p);\n    start++;\n  }\n}\n\nint main() {\n  int a[10] = {1, 450, 3, 4, 56, 12, 123, 45, 23, 6};\n  struct node *root = malloc(sizeof(struct node));\n  root-\u003eleft = root-\u003eright = NULL;\n  root-\u003evalue = a[0];\n  bst_build(root, a, 1, 10);\n  bst_inorder_traversal(root);\n  printf(\"root %p %d\\n\", root, root-\u003evalue);\n  struct node *ans = bst_search(root, root, 56, 0);\n  if (ans != NULL) {\n    printf(\"ans value %d\\n\", ans-\u003evalue);\n    bst_delete(ans, ans-\u003eright, 1);\n    bst_preorder_traversal(root);\n    bst_inorder_traversal(root);\n    bst_postorder_traversal(root);\n  }\n}\n```\n\n```c++\n/**\n *quickSort , 快速排序，传入要排序的数组和需要排序的范围[left, right]\n *从小到大\n */\nvoid quickSort(int left, int right, int array[]){\n\n    int i = left,j = right,x = array[(left+right)/2];\n    do{\n        while(array[i] \u003c x)i++;\n        while(array[j] \u003e x)j--;//使左边的值都比右边的小\n        if(i \u003c= j) {std::swap(array[i++],array[j--]);}\n    }while(i \u003c j);//i \u003e= j\n    if(i \u003c right)quickSort(i,right,array);\n    if(j \u003e left)quickSort(left,j,array);\n\n}\n\n```\n\n```c\n/**\n *heapSort 堆排序模板 （大根堆）\n */\nint mySwap(int *a,int *b){\nif(a == b) return;\n\t(*a) = (*a) ^ (*b);\n\t(*b) = (*a) ^ (*b);\n\t(*a) = (*a) ^ (*b);\n    return 1;\n}\t\nint sift(int array[],int k,int m)//one-based\n{\n//把k到m范围内的值调整为大根堆\n    int i = k,j = i\u003c\u003c1;//置i为要筛的节点 j 为i的左孩子\n    while(j \u003c= m){//仍然在范围之内\n        if(j \u003c m \u0026\u0026 array[j] \u003c array[j+1]){//右孩子存在 且左孩子小于右孩子\n            j++;//因为要建大根堆 所以选择孩子中较大者进行交换\n        }\n        if(array[i] \u003e array[j]){\n            break;//不需要再向下比较 因为之前也是调整过的大根堆\n        }\n        else{\n            mySwap(\u0026array[i],\u0026array[j]);\n            i = j;j = (i\u003c\u003c1);//被筛节点移动到j节点 计算左孩子\n        }\n    }\n    return 1;\n}\nint heapSort(int array[],int n){// one-based 从1开始保存的 到n结束 left_child = 2*parent\n    int i;\n    for(i = n\u003e\u003e1;i \u003e= 1;i--){\n        sift(array,i,n);//初始建堆 从 最后一个非终端节点到 1\n    }\n    for(i  = 1;i \u003c n;i++){//重复执行移走堆顶并重建堆的操作\n        mySwap(\u0026array[1],\u0026array[n-i+1]);//从n到2 不断和堆顶交换 one-based\n        sift(array,1,n - i);//重建堆\n    }\n    return 1;\n}\n```\n\n#### 11. 递归\n\n```c\n/**\n *汉诺塔 递归实现\n */\nint move(int n,char x,char y){\n    printf(\"move %d from %c to %c\\n\",n,x,y);//输出移动过程\n    return 1;\n}\nint hanoi(int n,char a,char b,char c){//将n个盘子借助b从a移动到c\n    if(n==1){move(1,a,c);}\n    else{\n        hanoi(n-1,a,c,b);//把n-1个盘子借助c从a移动到b\n        move(n,a,c);//把第n个盘子从a移动到c\n        hanoi(n-1,b,a,c);//将n-1个盘子借助a从b移动到c\n    }\n    return 1;\n}\n```\n\n#### 12. 链表\n\n```c\n/**\n *构建一个未赋值的循环单链表 至少有头和尾两个节点\n */\nstruct node{\n    int \tvalue;\n    struct node *next;\n};\nstruct node *constructRecurrentSingleChain(int start,int end){\n    struct node *head = (struct node*)malloc(sizeof(struct node));\n    struct node *tail = (struct node*)malloc(sizeof(struct node));\n\n    head-\u003enext = tail;\n    tail-\u003enext = head;\n    //head-\u003evalue= -1;\n    //tail-\u003evalue= -1;\n    while(start != end){\n        struct node *new_node = (struct node*)malloc(sizeof(struct node));\n        //new_node-\u003evalue     = start;根据具体情况进行赋值\n        new_node-\u003enext        = head;\n        tail-\u003enext            = new_node;\n        tail                  = new_node;\n        start++;\n    }\n    return head;\n}\n```\n\n```c\n/**\n *构建未赋值的循环双链表 至少有头和尾两个节点\n */\nstruct node{\n    int value;\n    struct node *prev;\n    struct node *next;\n};\nstruct node *constructRecurrentDoubleChain(int start,int end){\n    struct node *head = (struct node*)malloc(sizeof(struct node));\n    struct node *tail = (struct node*)malloc(sizeof(struct node));\n\n    head-\u003eprev = tail;\n    head-\u003enext = tail;\n    tail-\u003enext = head;\n    tail-\u003eprev = head;\n    //head-\u003evalue= -1;\n    //tail-\u003evalue= -1;\n    while(start != end){\n        struct node *new_node = (struct node*)malloc(sizeof(struct node));\n        //new_node-\u003evalue       = start;\n        tail-\u003enext            = new_node;\n        head-\u003eprev            = new_node;\n        new_node-\u003eprev        = tail;\n        new_node-\u003enext        = head;\n        tail                  = new_node;\n        start++;\n    }\n    return head;\n}\n```\n\n#### 13. 大数\n\n```c++\n/**\n *大数的加法 乘法运算\n *效率很低 不能用于算大数阶乘\n */\n class BigInteger\n {\npublic:\n\n     BigInteger();\n     BigInteger(int);\n     BigInteger(string);\n     bool Display();\n     friend BigInteger operator +(const BigInteger\u0026,const BigInteger\u0026);\n     friend BigInteger operator *(const BigInteger\u0026,const BigInteger\u0026);\n     friend ostream\u0026   operator\u003c\u003c(std::ostream\u0026,BigInteger\u0026);\n\nprivate:\n\n     static const int max_len = 100000;\n\n public:\n\n     int len;\n     int array[max_len];\n\n }; \n BigInteger:: BigInteger(){\n\n     memset(array,0,sizeof(array));\n     //或者将sizeof(array) 换成 max_len*4\n     len = 0;\n\n }\n BigInteger:: BigInteger(string digit){\n\n     memset(array,0,sizeof(array));\n     len = digit.size();\n     for(int i = 0;i \u003c len;i++){\n         array[i] = digit[len - i - 1] - '0';\n     }\n\n }\n BigInteger:: BigInteger(int digit){\n\n     memset(array,0,sizeof(array));\n     if(digit == 0)len = 1;\n     else\t\tlen = 0;\n     while(digit != 0){\n         array[len++] = digit % 10;\n         digit        = digit / 10;\n     }\n\n }\n bool BigInteger:: Display(){\n\n     for(int i = len - 1;i \u003e= 0;i--) cout \u003c\u003c array[i];\n     return true;\n\n }\n std::ostream\u0026 operator\u003c\u003c(ostream \u0026out, BigInteger \u0026digit){\n\n     digit.Display(); return out;\n\n }\n BigInteger operator +(const BigInteger \u0026augend, const BigInteger \u0026addend){\n\n     BigInteger result;\n     result.len = max(augend.len,addend.len);\n     for(int i = 0;i \u003c result.len;i++)\n         result.array[i] = augend.array[i] + addend.array[i];\n     for(int i= 0;i \u003c result.len;i++){\n         if(result.array[i] \u003e= 10){\n             result.array[i] -= 10;\n             result.array[i+1]++;\n         }\n     }\n     if(result.array[result.len] \u003e 0){result.len++;}\n     return result;\n\n }\n BigInteger operator *(const BigInteger \u0026multiplicand, const BigInteger \u0026multiplier)\n {\n\n     BigInteger result;\n     result.len = multiplicand.len + multiplier.len - 1;\n     for(int i = 0;i \u003c multiplicand.len;i++){\n         for(int j = 0;j \u003c multiplier.len;j++)\n             result.array[i + j] += multiplicand.array[i]*multiplier.array[j];\n     }\n     for(int i = 0;i \u003c result.len;i++){\n         if(result.array[i] \u003e 9){\n             result.array[i+1] += result.array[i] / 10;\n             result.array[i]   %= 10;\n         }\n     }\n     if(result.array[result.len] \u003e 0) result.len++;\n     while(result.len \u003e 1 \u0026\u0026 result.array[result.len-1] == 0)\n         result.len--;//为0的时候不用去掉第一位的0\n     return result;\n\n }\n\n```\n\n```c\n/**\n *n的阶乘 结果为大数，保存在array数组中\n *end - 1 到 0为结果 (end-1)在前,为高位\n */\nint factorial(int *array,int n){\n    int end = 1; array[0] = 1;\n    for(int i = 2;i \u003c= n;i++){\n        int r = 0;\n        for(int j = 0;j \u003c end;j++){\n            //乘以每一位\n            int t = array[j]*i+r;\n            array[j] = t%10;\n            r = t/10;\n        }\n        while(r){\n            array[end++] = r % 10;\n            r /= 10;\n        }\n    }\n    return end;\n}\n```\n\n```c\n/**\n *大数模板(浙大)\n *注意这里的int可能会超 void div(bignum_t a,const int b,int\u0026 c)\n */\n#define DIGIT \t3//千进制\n#define DEPTH\t1000//千进制\n#define MAX     1000//位数\ntypedef int bignum_t[MAX+1];\n\nint read(bignum_t a,istream\u0026 is=cin){\n\tchar buf[MAX*DIGIT+1],ch;\n\tint i,j;\n\tmemset((void*)a,0,sizeof(bignum_t));\n\tif (!(is\u003e\u003ebuf))\treturn 0;\n\tfor (a[0]=strlen(buf),i=a[0]/2-1;i\u003e=0;i--)\n\t\tch=buf[i],buf[i]=buf[a[0]-1-i],buf[a[0]-1-i]=ch;\n\tfor (a[0]=(a[0]+DIGIT-1)/DIGIT,j=strlen(buf);j\u003ca[0]*DIGIT;buf[j++]='0');\n\tfor (i=1;i\u003c=a[0];i++)\n\t\tfor (a[i]=0,j=0;j\u003cDIGIT;j++)\n\t\t\ta[i]=a[i]*10+buf[i*DIGIT-1-j]-'0';\n\tfor (;!a[a[0]]\u0026\u0026a[0]\u003e1;a[0]--);\n\treturn 1;\n}\n\nvoid write(const bignum_t a,ostream\u0026 os=cout){\n\tint i,j;\n\tfor (os\u003c\u003ca[i=a[0]],i--;i;i--)\n\t\tfor (j=DEPTH/10;j;j/=10)\n\t\t\tos\u003c\u003ca[i]/j%10;\n}\n\nint comp(const bignum_t a,const bignum_t b){\n\tint i;\n\tif (a[0]!=b[0])\n\t\treturn a[0]-b[0];\n\tfor (i=a[0];i;i--)\n\t\tif (a[i]!=b[i])\n\t\t\treturn a[i]-b[i];\n\treturn 0;\n}\n\nint comp(const bignum_t a,const int b){\n\tint c[12]={1};\n\tfor (c[1]=b;c[c[0]]\u003e=DEPTH;c[c[0]+1]=c[c[0]]/DEPTH,c[c[0]]%=DEPTH,c[0]++);\n\treturn comp(a,c);\n}\n\nint comp(const bignum_t a,const int c,const int d,const bignum_t b){\n\tint i,t=0,O=-DEPTH*2;\n\tif (b[0]-a[0]\u003cd\u0026\u0026c)\n\t\treturn 1;\n\tfor (i=b[0];i\u003ed;i--){\n\t\tt=t*DEPTH+a[i-d]*c-b[i];\n\t\tif (t\u003e0) return 1;\n\t\tif (t\u003cO) return 0;\n\t}\n\tfor (i=d;i;i--){\n\t\tt=t*DEPTH-b[i];\n\t\tif (t\u003e0) return 1;\n\t\tif (t\u003cO) return 0;\n\t}\n\treturn t\u003e0;\n}\n\nvoid add(bignum_t a,const bignum_t b){\n\tint i;\n\tfor (i=1;i\u003c=b[0];i++)\n\t\tif ((a[i]+=b[i])\u003e=DEPTH)\n\t\t\ta[i]-=DEPTH,a[i+1]++;\n\tif (b[0]\u003e=a[0])\n\t\ta[0]=b[0];\n\telse\n\t\tfor (;a[i]\u003e=DEPTH\u0026\u0026i\u003ca[0];a[i]-=DEPTH,i++,a[i]++);\n\ta[0]+=(a[a[0]+1]\u003e0);\n}\n\nvoid add(bignum_t a,const int b){\n\tint i=1;\n\tfor (a[1]+=b;a[i]\u003e=DEPTH\u0026\u0026i\u003ca[0];a[i+1]+=a[i]/DEPTH,a[i]%=DEPTH,i++);\n\tfor (;a[a[0]]\u003e=DEPTH;a[a[0]+1]=a[a[0]]/DEPTH,a[a[0]]%=DEPTH,a[0]++);\n}\n\nvoid sub(bignum_t a,const bignum_t b){\n\tint i;\n\tfor (i=1;i\u003c=b[0];i++)\n\t\tif ((a[i]-=b[i])\u003c0)\n\t\t\ta[i+1]--,a[i]+=DEPTH;\n\tfor (;a[i]\u003c0;a[i]+=DEPTH,i++,a[i]--);\n\tfor (;!a[a[0]]\u0026\u0026a[0]\u003e1;a[0]--);\n}\n\nvoid sub(bignum_t a,const int b){\n\tint i=1;\n\tfor (a[1]-=b;a[i]\u003c0;a[i+1]+=(a[i]-DEPTH+1)/DEPTH,a[i]-=(a[i]-DEPTH+1)/DEPTH*DEPTH,i++);\n\tfor (;!a[a[0]]\u0026\u0026a[0]\u003e1;a[0]--);\n}\n\nvoid sub(bignum_t a,const bignum_t b,const int c,const int d){\n\tint i,O=b[0]+d;\n\tfor (i=1+d;i\u003c=O;i++)\n\t\tif ((a[i]-=b[i-d]*c)\u003c0)\n\t\t\ta[i+1]+=(a[i]-DEPTH+1)/DEPTH,a[i]-=(a[i]-DEPTH+1)/DEPTH*DEPTH;\n\tfor (;a[i]\u003c0;a[i+1]+=(a[i]-DEPTH+1)/DEPTH,a[i]-=(a[i]-DEPTH+1)/DEPTH*DEPTH,i++);\n\tfor (;!a[a[0]]\u0026\u0026a[0]\u003e1;a[0]--);\n}\n\nvoid mul(bignum_t c,const bignum_t a,const bignum_t b){\n\tint i,j;\n\tmemset((void*)c,0,sizeof(bignum_t));\n\tfor (c[0]=a[0]+b[0]-1,i=1;i\u003c=a[0];i++)\n\t\tfor (j=1;j\u003c=b[0];j++)\n\t\t\tif ((c[i+j-1]+=a[i]*b[j])\u003e=DEPTH)\n\t\t\t\tc[i+j]+=c[i+j-1]/DEPTH,c[i+j-1]%=DEPTH;\n\tfor (c[0]+=(c[c[0]+1]\u003e0);!c[c[0]]\u0026\u0026c[0]\u003e1;c[0]--);\n}\n\nvoid mul(bignum_t a,const int b){\n\tint i;\n\tfor (a[1]*=b,i=2;i\u003c=a[0];i++){\n\t\ta[i]*=b;\n\t\tif (a[i-1]\u003e=DEPTH)\n\t\t\ta[i]+=a[i-1]/DEPTH,a[i-1]%=DEPTH;\n\t}\n\tfor (;a[a[0]]\u003e=DEPTH;a[a[0]+1]=a[a[0]]/DEPTH,a[a[0]]%=DEPTH,a[0]++);\n\tfor (;!a[a[0]]\u0026\u0026a[0]\u003e1;a[0]--);\n}\n\nvoid mul(bignum_t b,const bignum_t a,const int c,const int d){\n\tint i;\n\tmemset((void*)b,0,sizeof(bignum_t));\n\tfor (b[0]=a[0]+d,i=d+1;i\u003c=b[0];i++)\n\t\tif ((b[i]+=a[i-d]*c)\u003e=DEPTH)\n\t\t\tb[i+1]+=b[i]/DEPTH,b[i]%=DEPTH;\n\tfor (;b[b[0]+1];b[0]++,b[b[0]+1]=b[b[0]]/DEPTH,b[b[0]]%=DEPTH);\n\tfor (;!b[b[0]]\u0026\u0026b[0]\u003e1;b[0]--);\n}\n\nvoid div(bignum_t c,bignum_t a,const bignum_t b){\n\tint h,l,m,i;\n\tmemset((void*)c,0,sizeof(bignum_t));\n\tc[0]=(b[0]\u003ca[0]+1)?(a[0]-b[0]+2):1;\n\tfor (i=c[0];i;sub(a,b,c[i]=m,i-1),i--)\n\t\tfor (h=DEPTH-1,l=0,m=(h+l+1)\u003e\u003e1;h\u003el;m=(h+l+1)\u003e\u003e1)\n\t\t\tif (comp(b,m,i-1,a)) h=m-1;\n\t\t\telse l=m;\n\tfor (;!c[c[0]]\u0026\u0026c[0]\u003e1;c[0]--);\n\tc[0]=c[0]\u003e1?c[0]:1;\n}\n\nvoid div(bignum_t a,const int b,long long \u0026 c){\n\tint i;\n\tfor (c=0,i=a[0];i;c=c*DEPTH+a[i],a[i]=c/b,c%=b,i--);\n\tfor (;!a[a[0]]\u0026\u0026a[0]\u003e1;a[0]--);\n}\n\nvoid sqrt(bignum_t b,bignum_t a){\n\tint h,l,m,i;\n\tmemset((void*)b,0,sizeof(bignum_t));\n\tfor (i=b[0]=(a[0]+1)\u003e\u003e1;i;sub(a,b,m,i-1),b[i]+=m,i--)\n\t\tfor (h=DEPTH-1,l=0,b[i]=m=(h+l+1)\u003e\u003e1;h\u003el;b[i]=m=(h+l+1)\u003e\u003e1)\n\t\t\tif (comp(b,m,i-1,a)) h=m-1;\n\t\t\telse l=m;\n\tfor (;!b[b[0]]\u0026\u0026b[0]\u003e1;b[0]--);\n\tfor (i=1;i\u003c=b[0];b[i++]\u003e\u003e=1);\n}\n\nint length(const bignum_t a){\n\tint t,ret;\n\tfor (ret=(a[0]-1)*DIGIT,t=a[a[0]];t;t/=10,ret++);\n\treturn ret\u003e0?ret:1;\n}\n\nint digit(const bignum_t a,const int b){\n\tint i,ret;\n\tfor (ret=a[(b-1)/DIGIT+1],i=(b-1)%DIGIT;i;ret/=10,i--);\n\treturn ret%10;\n}\n\nint zeronum(const bignum_t a){\n\tint ret,t;\n\tfor (ret=0;!a[ret+1];ret++);\n\tfor (t=a[ret+1],ret*=DIGIT;!(t%10);t/=10,ret++);\n\treturn ret;\n}\n\nvoid comp(int* a,const int l,const int h,const int d){\n\tint i,j,t;\n\tfor (i=l;i\u003c=h;i++)\n\t\tfor (t=i,j=2;t\u003e1;j++)\n\t\t\twhile (!(t%j))\n\t\t\t\ta[j]+=d,t/=j;\n}\n\nvoid convert(int* a,const int h,bignum_t b){\n\tint i,j,t=1;\n\tmemset(b,0,sizeof(bignum_t));\n\tfor (b[0]=b[1]=1,i=2;i\u003c=h;i++)\n\t\tif (a[i])\n\t\t\tfor (j=a[i];j;t*=i,j--)\n\t\t\t\tif (t*i\u003eDEPTH)\n\t\t\t\t\tmul(b,t),t=1;\n\tmul(b,t);\n}\n\nvoid combination(bignum_t a,int m,int n){\n\tint* t=new int[m+1];\n\tmemset((void*)t,0,sizeof(int)*(m+1));\n\tcomp(t,n+1,m,1);\n\tcomp(t,2,m-n,-1);\n\tconvert(t,m,a);\n\tdelete []t;\n}\n\nvoid permutation(bignum_t a,int m,int n){\n\tint i,t=1;\n\tmemset(a,0,sizeof(bignum_t));\n\ta[0]=a[1]=1;\n\tfor (i=m-n+1;i\u003c=m;t*=i++)\n\t\tif (t*i\u003eDEPTH)\n\t\t\tmul(a,t),t=1;\n\tmul(a,t);\n}\n```\n\n#### 14. 并查集\n\n```c\nint father[15];\nvoid makeSet(){\n    for(inti = 0;i \u003c= n;i++){\n        father[i] = i;\n    }\n}\nint findSet(int x){\n    if(x != father[x]){\n        father[x] = findSet(father[x]);\n    }\n    return father[x];\n}\nvoid unionSet(int x,int y){\n    x = findSet(x);\n    y = findSet(y);\n    father[x] = y;\n}\n```\n\n#### 15. 状态压缩\n\n```c\n/**\n *状态压缩法求阶乘，虽然可以求但这只是状态压缩恰好的一个性质 它主要用在动态规划中\n *注释里的是f[13] = f[12] + f[5] + f[9] 的工作过程，t -= t \u0026 -t 就是将最开始的t的每位1取出来，取      \n *出来的那位1和原来的值t异或就把那位1变成0了，有点别扭 :( \n */\t\nlong long f[1\u003c\u003c20] = {};\nf[0] = 1;//f[2^0 - 1] = f[0] = 1 (0的阶乘为1)\nfor(int i = 1;i \u003c (1\u003c\u003cn);i++){// 1 到 2^n - 1\n    for(int t = i; t \u003e 0; t -= (t \u0026 -t)){\n        //f(01101) = f(00101) + f(01001) + f(01100)\n        //1 t = 13\n        //2 13 -= 1\n        //3 12 -= 4\n        //4 8  -= 8\n        f[i] += f[i ^ (t \u0026 -t)];//将某些位变为0 计算和\n        //1 f[(01101) ^ (01101 \u0026 10011)] = f[01100]\n        //2 f[(01101) ^ (01100 \u0026 10100)] = f[01001]\n        //3 f[(01101) ^ (01000 \u0026 11000)] = f[00101]\n    }\n}\n// n! = f[(1\u003c\u003cn)-1]\n```\n\n#### 16. 树状数组\n\n```c\n/**\n *一维树状数组,树状数组C[],输入的数组A[]\n *A[] C[]都是从1开始的 在build之前C[]初始化为0\n */\n\nint lowbit(int x){\n    return x \u0026 (x^(x-1));//这一步是把x的二进制表示中的最低位1取出来\n    //x   = ***100\n    //x-1 = ***011\n    //x ^ (x-1) = 000111\n    //x \u0026 (x ^ (x-1)) = 000100\n\n    //return x\u0026(-x);//另一种写法\n    //x  = ***100\n    //-x = ---011 + 1 = ---100;\n    //x\u0026-x = 000100;\n}\nvoid add(int i,int v,int upper){//对A[i]进行加v操作 同时更新C\n    //对A[i]的更新直接不要放在这里 因为build也要调用该函数\n    while(i \u003c= upper){\n        C[i] += v; i += lowbit(i);\n    }\n}\nvoid build(int begin,int end){//根据A[begin]到A[end]构建树状数组\n    while(begin \u003c= end){\n        add(begin,A[begin],end);\n    }\n}\nint sum(int i){//求前n项和\n    int sum = 0;\n    while(i \u003e= 1){\n        sum += C[i]; i -= lowbit(i);\n    }\n    return sum;\n}\n```\n\n```c\n/**\n *二维树状数组\n *二维树状数组和一维几乎一样\n */\n\nint lowbit(int x){\n    return x \u0026 (x^(x-1));\n}\nvoid add(int i,int j,int v,int upper){//增加\n    int t_i,t_j;\n    for(t_i = i;t_i \u003c= upper;t_i += lowbit(t_i)){\n        for(t_j = j;t_j \u003c= upper;t_j += lowbit(t_j)){\n            C[t_i][t_j] += v;\n        }\n    }\n}\nint query(int i,int j){//查询\n    int sum = 0,t_i,t_j;\n    for(t_i = i;t_i \u003e 0;t_i -= lowbit(t_i)){\n        for(t_j = j;t_j \u003e 0;t_j -= lowbit(t_j)){\n            sum += C[t_i][t_j];\n        }\n    }\n    return sum;\n}\n```\n\n#### 17. 线段树\n\n```c\n/**\n *树状数组是前序和，应用范围要窄，线段树可以求区间和、区间最大值等等\n *下面是求线段树求区间和的示例，可以根据具体情况修改\n */\n \n#define MAX 100000\nstruct node{\n    int left,right;\n    long long sum,weight;\n}tree[MAX];\nint A[MAX];//MAX_n\nvoid build(int i,int a,int b){//构建线段树 i为层数 初始为1 ，传入区间[a,b]\n    //tree[i].left tree[i].right为节点i的左右边界\n    if(a != b){\n        tree[i].left = a;tree[i].right= b;\n        build(i\u003c\u003c1,a,(a+b)\u003e\u003e1);//递归构造左子树\n        build((i\u003c\u003c1)+1,((a+b)\u003e\u003e1)+1,b);//递归构造右子树\n        tree[i].sum  = tree[i\u003c\u003c1].sum + tree[(i\u003c\u003c1)+1].sum;//回溯 左右子树的和等于父节点\n    }\n    else{\n        tree[i].left = tree[i].right = a;\n        tree[i].sum  = A[a];//A[]为输入的数组\n        return;\n    }\n    tree[i].weight = 0;\n}\nint add(int i,int a,int b,int v){//将某个区间的所有值加上v\n    if(tree[i].left == a \u0026\u0026 tree[i].right == b){\n        //恰好是这个区间\n        tree[i].weight += v;//将这个值保存而不是直接累加\n\t   //查询的时候再进行更新 节省时间开销\n        return 1;\n    }\n    else{\n        //不是该区间但是属于该区间\n        tree[i].sum += v*(b - a + 1);\n    }\n    int mid = (tree[i].left+tree[i].right) \u003e\u003e 1;\n    if(a \u003c= mid \u0026\u0026 b \u003e mid){\n        add(i\u003c\u003c1,a,mid,v);\n        add((i\u003c\u003c1)+1,mid+1,b,v);\n    }\n    else{\n        add((i\u003c\u003c1)+(b\u003c=mid?0:1),a,b,v);\n    }\n    return 1;\n}\nlong long query(int i,int a,int b){//查询某个区间的所有值的和\n    int mid = (tree[i].left+tree[i].right) \u003e\u003e 1;\n    if(tree[i].left == a \u0026\u0026 tree[i].right == b){\n        return tree[i].sum + (tree[i].right - tree[i].left + 1)*tree[i].weight;\n    }\n    else if(tree[i].weight != 0){\n        tree[i].sum            += (tree[i].right - tree[i].left + 1)*tree[i].weight;//首先更新自己\n        tree[i\u003c\u003c1].weight      += tree[i].weight;//然后传递给左右子树\n        tree[(i\u003c\u003c1)+1].weight  += tree[i].weight;\n        tree[i].weight = 0;//自身清零\n    }\n    if(a \u003c= mid \u0026\u0026 b \u003e mid){\n        return query(i\u003c\u003c1,a,mid) + query((i\u003c\u003c1)+1,mid+1,b);\n    }\n    return query((i\u003c\u003c1) + (b\u003c=mid?0:1),a,b);\n}\n```\n\n```c\n/**\n *二维线段树\n *调用add,query,build时注意传参时的大小顺序，左小于右\n *二维线段树的x维度和y维度表示的意义不一定是一样的\n *下面是求平面上的矩形面积和(去掉重复区域后的面积和)，可以根据具体情况修改\n */\n#define MAX 1500\nvector\u003cdouble\u003e x;\nvector\u003cdouble\u003e y;//用于离散化\nstruct y_node{\n    int left,right;\n    double len;//被覆盖的区间长度\n};\t\nstruct x_node{\n    int left,right;\n    double area;//被覆盖的面积\n    struct y_node sub[MAX];\n}tree[MAX];\n\nvoid buildSub(int i,int j,int yl,int yr){\n    tree[i].sub[j].left  = yl;\n    tree[i].sub[j].right = yr;\n    tree[i].sub[j].len = 0;\n    if(yr - yl == 1){\n        return;\n    }\n    buildSub(i,j\u003c\u003c1,yl,(yl+yr)\u003e\u003e1);\n    buildSub(i,(j\u003c\u003c1)+1,((yl+yr)\u003e\u003e1),yr);//最小元是个线段所以不加1\n}\nvoid build(int i,int xl,int xr,int ylm,int yrm){\n    tree[i].left = xl;tree[i].right= xr;tree[i].area = 0;\n    if(xr - xl == 1){\n        buildSub(i,1,ylm,yrm);//建立子树 只对叶子节点建立子树\n        return;\n    }\n    build(i\u003c\u003c1,xl,(xl+xr)\u003e\u003e1,ylm,yrm);\n    build((i\u003c\u003c1)+1,((xl+xr)\u003e\u003e1),xr,ylm,yrm);\n}\nvoid addSub(int i,int j,int yl,int yr){\n    if(tree[i].sub[j].left == yl \u0026\u0026 tree[i].sub[j].right == yr){\n        tree[i].sub[j].len = y[tree[i].sub[j].right] - y[tree[i].sub[j].left];\n        return;\n    }\n    int mid = (tree[i].sub[j].left + tree[i].sub[j].right)\u003e\u003e1;\n    if(yl \u003c mid \u0026\u0026 yr \u003e mid){\n        addSub(i,(j\u003c\u003c1),yl,mid);\n        addSub(i,(j\u003c\u003c1)+1,mid,yr);\n    }\n    else{\n        addSub(i,(j\u003c\u003c1)+((yl \u003e= mid)?1:0),yl,yr);\n    }\n    tree[i].sub[j].len = mymax(tree[i].sub[j].len,tree[i].sub[(j\u003c\u003c1)].len + tree[i].sub[(j\u003c\u003c1)+1].len);\n}\nvoid add(int i,int xl,int xr,int yl,int yr){//\n\n    if(tree[i].right - tree[i].left == 1){//元区间\n        addSub(i,1,yl,yr);//对y坐标加边 并计算长度\n        tree[i].area = tree[i].sub[1].len*(x[xr]-x[xl]);//计算面积\n        return;\n    }\n    int mid = (tree[i].left + tree[i].right)\u003e\u003e1;\n    if(xl \u003c mid \u0026\u0026 xr \u003e mid){\n        add((i\u003c\u003c1),xl,mid,yl,yr);\n        add((i\u003c\u003c1)+1,mid,xr,yl,yr);\n    }\n    else{\n        add((i\u003c\u003c1)+((xl \u003e= mid)?1:0),xl,xr,yl,yr);\n    }\n    //更新面积\n    tree[i].area = tree[(i\u003c\u003c1)].area + tree[(i\u003c\u003c1)+1].area;\n}\ndouble querySub(int i,int j,int ya,int yb){\n    if(tree[i].sub[j].left == ya \u0026\u0026 tree[i].sub[j].right == yb){\n        return tree[i].sub[j].len;\n    }\n    else{\n        //不是目标区间但包含目标区间\n        //do something\n    }\n    int mid = (ya+yb)\u003e\u003e1;\n    if(ya \u003c= mid \u0026\u0026 yb \u003e mid){\n        return querySub(i,j\u003c\u003c1,ya,mid) + querySub(i,(j\u003c\u003c1)+1,mid,yb);\n    }\n    else return querySub(i,(j\u003c\u003c1)+(yb\u003c=mid?0:1),ya,yb);\n}\ndouble query(int i,int xa,int xb,int ya,int yb){\n    if(tree[i].left == xa \u0026\u0026 tree[i].right == xb){\n        return tree[i].area;\n    }\n    else{\n        //do something\n    }\n    int mid = (xa+xb)\u003e\u003e1;\n    if(xa \u003c= mid \u0026\u0026 xb \u003e mid){\n        return query(i\u003c\u003c1,xa,mid,ya,yb) + query((i\u003c\u003c1)+1,mid,xb,ya,yb);\n    }\n    else return query((i\u003c\u003c1)+(xb\u003c=mid?0:1),xa,xb,ya,yb);\n}\n//main中的离散化代码\nsort(x.begin(),x.end());\nsort(y.begin(),y.end());//排序之后去重\nx.resize(unique(x.begin(),x.end()) - x.begin());\ny.resize(unique(y.begin(),y.end()) - y.begin());\n```\n\n#### 18. Trie树\n\n```c\n/**\n *trie树，hash的方式，用空间换时间 注意别忘了创建根节点\n */\n#define MAX 256 //每个节点可能有多少个孩子\nstruct node{\n    ///数据域\n    int used;//标记是否有对应的字母\n    struct node *next[MAX];\n};\nvoid create(struct node *t){\n    for(int i = 0;i \u003c MAX;i++){\n        t-\u003enext[i] = new struct node;\n        ///initialize\n    }\n}\t\nvoid trieInsert(struct node *curr,const char *str,const int len){\n    for(int i = 0;i \u003c len;i++){\n        //在当前节点的孩子中找\n        int index = (int)str[i];\n        if(curr-\u003enext[index]-\u003eused == 0){//没有这个字母\n            curr-\u003enext[index]-\u003eused = 1;\n            create(curr-\u003enext[index]);//创建它的孩子\n        }\n        curr = curr-\u003enext[index];\n    }\n    ///do something\n}\n```\n\n#### 19. 矩阵\n\n```c\n/**\n *矩阵快速幂(2行2列)\n */\ntypedef double dataType;\nstruct matrix{\n    dataType mat[2][2];\n    matrix(){memset(mat,0,sizeof(mat));}//初始化为0\n    matrix(double v1,double v2,double v3,double v4){mat[0][0] = v1;mat[0][1] = v2;mat[1][0] = v3;mat[1][1]=v4;}\n    matrix operator*(const matrix \u0026b){\n        matrix rs;\n        for(int i = 0;i \u003c 2;i++){\n            for(int k = 0;k \u003c 2;k++){\n                for(int j = 0;j \u003c 2;j++){\n                    rs.mat[i][j] += mat[i][k]*b.mat[k][j];\n                }\n            }\n        }\n        return rs;\n    }\n};\t\nmatrix fastPower(matrix a,int po){\n    //a^po\n    matrix rs(1,0,0,1);//初始化为1\n    while(po){\n        if(po\u00261){rs = rs*a;}\n        a = a*a;po = (po\u003e\u003e1);\n    }\n    return rs;\n}\n```\n\n#### 20. 精度处理\n\n```c\n/**\n *返回0表示x==0，-1表示x \u003c 0, 1表示x大于0\n *complf(a-b) == 0, a == b 或者 fabs(a-b) \u003c eps\n *complf(a-b) != 0, a != b 或者 fabs(a-b) \u003e eps\n *complf(a-b) \u003c  0, a \u003c  b 或者 a - b \u003c -eps\n *complf(a-b) \u003e  0, a \u003e  b 或者 a - b \u003e eps\n *complf(a-b) \u003c= 0, a \u003c= b 或者 a - b \u003c eps\n *complf(a-b) \u003e= 0, a \u003e= b 或者 a - b \u003e -eps\n */\t\n#define eps 1e-8\nint complf(double x){ return x \u003c -eps?-1:((x \u003c eps)?0:1);}\n```\n\n#### 21. 动态规划\n\n```c\n/**\n *0-1 背包 （二维实现，可以优化到一维）\n *注释中所说的对象可以为一个物体，也可以为一种方案，视题目而定\n */\n\ndp[n+1][v+1];\nmemset(dp[0],0,sizeof(int)*(v+1));//不放任何对象时，不管背包容量多少的价值都是0\nfor(i = 1;i \u003c= n;i++){//从第一个对象开始\n    //处理第i 个对象，在当前背包容量为j的时候选还是不选这个对象\n    for(j = 0;j \u003c= v;j++){//枚举每个容量\n        if(volume[i] \u003e j){//这个对象肯定是不能放在容量为j的背包里的\n            //如果j \u003c volume[i]，相减之后就小于0了\n            dp[i][j] = dp[i-1][j];\n        }\n        else{//如果体积刚好等于剩余的容量也不一定会被放进去\n             //因为可能有其它几个对象组合之后的价值比这个单个对象的高\n            dp[i][j] = mymax(dp[i-1][j],dp[i-1][j-volume[i]]+weight[i]);\n        }\n    }\n}//结果保存在 dp[n][v]中，即对前n个对象做出取舍后的最优解\n```\n\n#### 22. 素数生成\n\n```c\n/**\n *筛法求素数 筛法求素数，找到[1,MAXL]的所有素数\n */\n#define MAXL 100000\n#define MAXC 50000\nbool not_prime[MAXL+1];//用于判断是否被筛掉 2的倍数都会被筛掉，但是没有标记\nint primeTable[MAXC];//保存素数\nlong long getPrime(){\n    long long i,j,step,prime_num = 1;\n    not_prime[0] = not_prime[1] = true;\n    primeTable[0] = 2;//第一个素数是2\n    for(i = 3;i \u003c= MAXL;i+=2){\n        if(not_prime[i] == false){\n            primeTable[prime_num++] = i;\n            for(j = i*i,step = 2*i;j \u003c= MAXL;j += step){not_prime[j] = true;}\n        }\n    }\n    return prime_num;\n}\n\n```\n\n#### 23. 素数测试\n\n```c\n/**\n *Miller-Rabin 素数测试\n *随机选取s个基 出错的概率至多为 1/(2^s)，50已经足够了\n *RAND_MAX包含在stdlib中，不同的库会有不同，但都至少为32767\n */\n\n/**\n *快速幂取模 返回 a^n mod m\n */\nlong long exp_mod(long long a,long long n,long long m){\n    //x*y mod m = ((x%m) * (y%m))%m\n    if(n == 1)\n        return a % m;\n    else if(n == 0)\n        return 1;\n    if(n\u00261){//奇数 a^n = (a^(n-1))*a\n        return ((a%m)*exp_mod(a,n-1,m)) % m;\n    }\n    else{//偶数 a^n = (a^(n\u003e\u003e1))^2\n        long long t = exp_mod(a,n\u003e\u003e1,m) % m;\n        return t*t%m;\n    }\n}\n\nint witness(int a,int n){\n    //a^(n-1) = 1 (mod n)\n    int t = 0,u = n-1;\n    while(!(u\u00261)){t++; u = (u\u003e\u003e1);}// n - 1 = u*(2^t)\n    long long x[2]; x[0] = x[1] = exp_mod(a,u,n);\n    for(int i = 1;i \u003c= t;i++){\n        x[1] = x[0]*x[0]%n;\n        if(x[1] == 1 \u0026\u0026 x[0] != 1 \u0026\u0026 x[0] != (n-1)){\n            return 1;//检测到一个非平凡平方根\n        }\n        x[0] = x[1];\n    }\n    if(x[1] != 1) return 1;\n    return 0;\n}\nint millerRabin(int n,int s = 50){\n    if(n == 2) return 1;\n    else if(!(n\u00261)) return 0;\n    for(int i = 0;i \u003c s;i++){\n        int a = (int)((rand()*1.0/RAND_MAX)*(n-2)) + 1;\n        if(witness(a,n)){\n            //a^(n-1) = 1 (mod n) 如果n为素数，那么对于a(1\u003c=a\u003c=n-1)都满足这个等式\n            return 0;//基数a是n为合数的证据\n        }\n    }\n    return 1;//几乎可以确定n是个素数\n}\n```\n\n#### 24. 最大公约数/最小公倍数\n\n```c\n/**\n *最大公约数 gcd\n *最小公倍数 lcm = a*b/gcd(a,b)\n */\nint gcd(int a,int b){\n\treturn b ? gcd( b,a % b ) : a;\n}\t\nint lcm(int a,int b){\n\treturn a/gcd(a,b)*b;\n}\n```\n\n```c\n/**\n *二进制欧几里得辗转相除法求gcd\n *传参的时候注意a \u003e= b\n */\ntypedef long long int64;\nint64 binaryGcd(int64 a,int64 b){\n    if(a == b) return a;\n    if((a\u00261) \u0026\u0026 (b\u00261)){\n        return binaryGcd(a-b,b);\n    }\t\n    else if((a\u00261) == 0 \u0026\u0026 (b\u00261) == 0){\n        return 2*binaryGcd(a\u003e\u003e1,b\u003e\u003e1);\n    }\n    else if((a\u00261)){\n        return binaryGcd(a,b\u003e\u003e1);\n    }\n    return binaryGcd(mymax(a\u003e\u003e1,b),mymin(a\u003e\u003e1,b));\n}\n```\n\n#### 25. 欧拉 phi 函数\n\n```c\n/**\n *欧拉phi函数  返回小于x且与x互质的数的个数\n */\nint euler_phi(int x){\n    int a = ceill(sqrt(x)),i,rs = x;\n    for(i = 2;i \u003c= a;i++){\n        if(x % i == 0){\n            rs -= rs/i;//减去 在这rs个元素中有i因子的 数 的个数\n            while(x % i == 0){x /= i;}//将x中含有i因子的数去掉\n            if(x == 1)break;//x已经到1了\n        }\n    }\n    if(x != 1) {rs -= (rs / x);}\n    return rs;\n}\n```\n\n#### 26. 快速幂取模\n\n```c\n/**\n *快速幂取模 返回 a^n mod m\n */\nint exp_mod(int a,int n,int m){\n    //x*y mod m = ((x%m) * (y%m))%m\n    if(n == 1)\n        return a % m;\n    else if(n == 0)\n        return 1 % m;\n    if(n\u00261){//奇数 a^n = (a^(n-1))*a\n        return ((a%m)*exp_mod(a,n-1,m)) % m;\n    }\n    else{//偶数 a^n = (a^(n\u003e\u003e1))^2\n        long long t = exp_mod(a,n\u003e\u003e1,m) % m;\n        return t*t%m;\n    }\n}\n```\n\n#### 27. 扩展欧几里得\n\n```c\n/**\n *扩展欧几里德 ax+by = gcd(a,b) 解出x,y\n */\nlong long extendedEuclid(long long a,long long b,long long \u0026x,long long \u0026y){\n    if(b == 0){\n        x = 1; y = 0; return a;\n    }\n    else{\n        long long gcd,x1,y1;\n        gcd = extendedEuclid(b,a%b,x1,y1);\n        x = y1; y = x1 - (a/b)*y1;\n        return gcd;\n    }\n}\n```\n\n#### 28. 梅森素数\n\n```c\n/**\n *扩展欧几里德 ax+by = gcd(a,b) 解出x,y\n */\nlong long extendedEuclid(long long a,long long b,long long \u0026x,long long \u0026y){\n    if(b == 0){\n        x = 1; y = 0; return a;\n    }\n    else{\n        long long gcd,x1,y1;\n        gcd = extenedEuclid(b,a%b,x1,y1);\n        x = y1; y = x1 - (a/b)*y1;\n        return gcd;\n    }\n}\n```\n\n#### 29. 最大流\n\n```c\n/**\n *最大流 传入源点 汇点和顶点数\n *graph[u][v]为u到v的剩余流量 （residual flow）\n *初始的流量根据具体情况而定，如果没有边相连流量为0\n *graph[v][u]为流过e(u,v)的流量\n */\n#define INF 1000000000\n#define MAX 100\nint Edmonds_Karp(int source, int sink, int vertex_num){\n    int maxFlow = 0;\n    while(true) {\n        int head, tail, pre_of[MAX], my_queue[MAX];\n        head = tail = 0;//初始化队列\n        my_queue[tail++] = source;//放入源点\n        memset(pre_of, -1, sizeof(pre_of));////(pre_of[v],v) 代表边(u,v)\n        while(head \u003c tail){\n            int u = my_queue[head++];\n            for(int v = 1; v \u003c= vertex_num; v ++) {//也可以从0开始\n                if(pre_of[v] == -1 \u0026\u0026 graph[u][v] \u003e 0){\n                    my_queue[tail++] = v;/*入队*/\n                    pre_of[v] = u;/*保存这条边*/\n                    if(u == sink)   break;\n                }\n            }\n            if(pre_of[sink] != -1) break; //找到增广路径\n        }\n        if(pre_of[sink] == -1) break;//没有增广路径\n        int min_flow = INF;\n        for(int v = sink; v != source; v = pre_of[v]) {\n            min_flow = mymin(min_flow, graph[pre_of[v]][v]);\n            //对pre保存的路径进行回溯找到最小的流(最大可流通流量)\n        }\n        maxFlow += min_flow;\n        for(int v = sink; v != source; v = pre_of[v]) {//更新流网络\n            graph[pre_of[v]][v] -= min_flow;\n            graph[v][pre_of[v]] += min_flow;\n        }\n    }\n    return maxFlow;\n}\n```\n\n```c\n/**\n *ISAP求最大流\n */\ntypedef  struct {\n\tint v, next, val;\n} edge;\nconst int MAXN = 20010;\nconst int MAXM = 500010;\n\nedge e[MAXM];\nint p[MAXN], eid;\n\ninline void init() {\n\tmemset(p, -1, sizeof(p));\n\teid = 0;\n}\n\n//有向\ninline void insert1(int from, int to, int val) {\n\te[eid].v = to;\n\te[eid].val = val;\n\te[eid].next = p[from];\n\tp[from] = eid++;\n\n\tswap(from, to);\n\n\te[eid].v = to;\n\te[eid].val = 0;\n\te[eid].next = p[from];\n\tp[from] = eid++;\n}\n\n//无向\ninline void insert2(int from, int to, int val) {\n\te[eid].v = to;\n\te[eid].val = val;\n\te[eid].next = p[from];\n\tp[from] = eid++;\n\n\tswap(from, to);\n\n\te[eid].v = to;\n\te[eid].val = val;\n\te[eid].next = p[from];\n\tp[from] = eid++;\n}\n\nint n, m; //n为点数 m为边数\nint h[MAXN];\nint gap[MAXN];\n\nint source, sink;\ninline int dfs(int pos, int cost) {\n\tif (pos == sink) {\n\t\treturn cost;\n\t}\n\tint j, minh = n - 1, lv = cost, d;\n\n\tfor (j = p[pos]; j != -1; j = e[j].next) {\n\t\tint v = e[j].v, val = e[j].val;\n\n\t\tif(val \u003e 0) {\n\t\t\tif (h[v] + 1 == h[pos]) {\n\t\t\t\tif (lv \u003c e[j].val) {\n\t\t\t\t\td = lv;\n\t\t\t\t} else {\n\t\t\t\t\td = e[j].val;\n\t\t\t\t}\n\n\t\t\t\td = dfs(v, d);\n\t\t\t\te[j].val -= d;\n\t\t\t\te[j ^ 1].val += d;\n\t\t\t\tlv -= d;\n\n\t\t\t\tif (h[source] \u003e= n) {\n\t\t\t\t\treturn cost - lv;\n\t\t\t\t}\n\n\t\t\t\tif (lv == 0) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (h[v] \u003c minh)\t{\n\t\t\t\tminh = h[v];\n\t\t\t}\n\t\t}\n\t}\n\n\tif (lv == cost) {\n\t\t--gap[h[pos]];\n\n\t\tif (gap[h[pos]] == 0) {\n\t\t\th[source] = n;\n\t\t}\n\n\t\th[pos] = minh + 1;\n\t\t++gap[h[pos]];\n\t}\n\n\treturn cost - lv;\n}\n\nint sap(int st, int ed) {\n\tsource = st;\n\tsink = ed;\n\tint ret = 0;\n\tmemset(gap, 0, sizeof(gap));\n\tmemset(h, 0, sizeof(h));\n\n\t//gap[st] = n;\n\tgap[0] = n;\n\twhile (h[st] \u003c n) {\n\t\tret += dfs(st, INT_MAX);\n\t}\n\treturn ret;\n}\n```\n\n#### 30. 最短路\n\n```c\n/**\n *SPFA可以用来求单源最短路径和求解差分约束\n *可以处理负边和负权回路\n */\t\n#define INF 1000000000\n#define MAX 50010//最大的点数，根据题目\nstruct node{int u,v,weight,next;}edge[10*MAX];//边数一般比点数多\nint head[MAX];int count = 0;\nvoid add(int u,int v,int c){//邻接表的加边操作\n    edge[count].u = u;edge[count].v = v;edge[count].weight = c;\n    edge[count].next = head[u];head[u] = count++;\n}\nint SPFA(int  ll,int rr){\n//根据具体情况对i点到起点的长度进行初始化\n    int d[MAX];for(int i = ll;i \u003c= rr;i++){d[i] = -INF;}d[ll] = 0;\n    queue\u003cint\u003e my_queue;my_queue.push(ll);//放入起点\n    bool in_queue[MAX] = {};//用于判断某点当前是否在队列中\n    while(!my_queue.empty()){\n        int start = my_queue.front();my_queue.pop();\n        in_queue[start] = false;//拿出来了 所以不在队列中了\n        for(int  i = head[start]; i != -1; i = edge[i].next){\n            int u = edge[i].u,v = edge[i].v,weight_of_uv = edge[i].weight;\n            if(d[v] \u003c d[u] + weight_of_uv){\n                d[v] = d[u] + weight_of_uv;\n                if(!in_queue[v]){\n                    //可以入队且不在队列中\n                    //可能会继续松弛表示可以入队\n                    my_queue.push(v);\n                    in_queue[v] = true;//标记为在队列中\n                }\n            }\n        }\n    }\n    return d[rr];//根据具体情况返回一个结果\n}\n```\n\n```c++\n/**\n *dijkstra求最短路，用优先队列优化\n *传入源点和顶点个数(注意顶点是从0还是1开始)\n *如果只计算源点到单个目的点的最短路，需将flag标记为1 并传入目的点\n *注意head, countt等初始化\n */\n#define MAX 1100\n#define INF 1000000000\nstruct node{\n\n    int u,v,w,next;//顶点结构体\n\n}edge[100100]; \nint head[MAX], countt=0; //每次都要初始化\nvoid add(int u, int v, int w){//加边\n\n    edge[countt].u = u;\n    edge[countt].v = v;\n    edge[countt].w = w;\n    edge[countt].next = head[u];head[u] = countt++;\n\n}\nstruct node2{\n\n    int ver,dist; //顶点和dist[ver]\n    node2(int v,int d){ver = v;dist = d;}\n\n}; \t\nbool operator \u003e (const node2 \u0026a, const node2 \u0026b){\n\n    //重载优先队列的 \u003e 运算符\n    if(a.dist \u003e b.dist)return true;\n    return false;\n\n}\nbool operator \u003c (const node2 \u0026a, const node2 \u0026b){\n\n    //重载优先队列的 \u003c 运算符\n    if(a.dist \u003c b.dist)return true;\n    return false;\n\n}\nint dijkstra(int source, int vertex_num, int end=-1, int flag=0){\n\n    int dist[MAX];\n    //优先队列(小根,top为最小值)\n    priority_queue\u003cnode2,vector\u003cnode2\u003e,greater\u003cnode2\u003e \u003e my;\n    for(int i = 1;i \u003c= vertex_num;i++){\n        dist[i] = INF;\n    }dist[source] = 0;\n    my.push(node2(source,0));//放入源点\n    int pre_of[MAX]; memset(pre_of,-1,sizeof(pre_of));\n    while(!my.empty()){\n        node2 u = my.top();my.pop();\n        if(flag \u0026\u0026 u.ver == end){return dist[u.ver];}\n        if(dist[u.ver] == INF) break;//肯定没有更小的\n        for(int i = head[u.ver];i != -1;i = edge[i].next){\n            int v = edge[i].v,w = edge[i].w;\n            if(dist[v] \u003e dist[u.ver] + w){\n                dist[v] = dist[u.ver] + w;\n                pre_of[v] = u.ver;//保存路径\n                my.push(node2(v,dist[v]));\n            }\n        }\n    }\n    ///dist[i]保存的是源点到所有i点的最短距离\n    return 1;\n\n}\n\n```\n\n#### 31. 最小生成树\n\n```c\n/**\n *kruskal求最小生成树\n */\n#define MAX 1000\nstruct node{int u,v,cost;}array[MAX*MAX];\nint edge_count;//边的数量\nint father[MAX];\nvoid makeSet(int n){\n    for(int i = 1;i \u003c= n;i++){\n        //根据具体条件对并查集初始化\n        father[i] = i;\n    }\n}\nint find(int x){\n    if(father[x] != x){\n        return father[x] = find(father[x]);\n    }\n    return father[x];\n}\nvoid unionSet(int x,int y){\n    //将x所在的集合合并到y所在的集合\n    father[find(x)] = find(y);\n}\nint kruskal(){\n    int total_cost = 0;//总花费\n    //对边排序\n    pseudocode: sort(array,array+edge_count);\n    for(int i = 0;i \u003c edge_count;i++){\n        if(find(array[i].u)==find(array[i].v)){\n            //端点在同一个集合的不能添加进去\n            //因为会构成回路\n            continue;\n        }\n        total_cost += array[i].cost;\n        unionSet(array[i].u,array[i].v);\n    }\n    return total_cost;\n}\n```\n\n#### 31. 有向图的强连通分量\n\n```c\n/**\n *Tarjan algorithm for strongly connected component\n *求强连通分量的tarjan算法,邻接表表示\n *注意数组的初始化\n */\nint dfs_order[MAX], lowest[MAX];\nint my_stack[MAX],visited[MAX],in_stack[MAX];\nint mark_num,top;\nstruct node{\n    int u,v,next;\n}edge[MAX*5];\nvoid tarjan_scc(int u){\n    dfs_order[u] = lowest[u] = mark_num++;\n    my_stack[top++] = u;visited[u] = 1;in_stack[u] = 1;\n    for(int i = head[u];i != -1;i = edge[i].next){\n        int v = edge[i].v;\n        if(!visited[v]){\n            tarjan_scc(v);\n            lowest[u] = mymin(lowest[u],lowest[v]);\n        }\n        else if(in_stack[v]){\n            lowest[u] = mymin(lowest[u],dfs_order[v]);\n        }\n    }\n    if(dfs_order[u] == lowest[u]){\n        int p;\n        do{\n            p = my_stack[--top];in_stack[p] = 0;\n            ///这里出栈的是当前的一个强连通分量\n            ///根据具体情况处理\n        }while(u != p);\n    }\n}\n```\n\n#### 32. 无向图的双连通分量\n\n```c\n/**\n *Tarjan algorithm for strongly connected component\n *求强连通分量的tarjan算法,邻接表表示\n *注意数组的初始化\n */\nint dfs_order[MAX], lowest[MAX];\nint my_stack[MAX],visited[MAX],in_stack[MAX];\nint mark_num,top;\nstruct node{\n    int u,v,next;\n}edge[MAX*5];\nvoid tarjan_scc(int u){\n    dfs_order[u] = lowest[u] = mark_num++;\n    my_stack[top++] = u;visited[u] = 1;in_stack[u] = 1;\n    for(int i = head[u];i != -1;i = edge[i].next){\n        int v = edge[i].v;\n        if(!visited[v]){\n            tarjan_scc(v);\n            lowest[u] = mymin(lowest[u],lowest[v]);\n        }\n        else if(in_stack[v]){\n            lowest[u] = mymin(lowest[u],dfs_order[v]);\n        }\n    }\n    if(dfs_order[u] == lowest[u]){\n        int p;\n        do{\n            p = my_stack[--top];in_stack[p] = 0;\n            ///这里出栈的是当前的一个强连通分量\n            ///根据具体情况处理\n        }while(u != p);\n    }\n}\n```\n\n#### 33. 二分图的最大匹配\n\n```c\n/**\n *二分图的最大匹配（邻接矩阵），交大模板\n *graph初始化为0，返回最大匹配数\n *注意要给nx ny赋值\n */\n#define MAX 510\nint nx,ny,graph[MAX][MAX],sy[MAX],cx[MAX],cy[MAX];\nint path(int u){\n    for(int v = 1; v \u003c= ny;v++){\n        if(graph[u][v] \u0026\u0026 !sy[v]){\n            sy[v] = 1;\n            if(!cy[v] || path(cy[v])){\n                cx[u] = v; cy[v] = u;\n                return 1;\n            }\n        }\n    }\n    return 0;\n}\nint maximumMatch(){\n    int i,ret = 0;\n    memset(cx,0,sizeof(cx));\n    memset(cy,0,sizeof(cy));\n    for(i = 1;i \u003c= nx;i++){\n        if(!cx[i]){//\n            memset(sy,0,sizeof(sy));\n            ret += path(i);\n        }\n    }\n    return ret;\n}\n```\n\n#### 34. 叉积/点与线段/线段与线段\n\n```c\nstruct point{double x,y;};\nstruct segment{point a,b;};\n/**\n *cross product\n *(p2-p1) X (q2-q1) -\u003e aXb\n *(p2.x-p1.x,p2.y-p1.y) X (q2.x-q1.x,q2.y - q1.y)\n *结果大于0说明 b到a为顺时针 等于0说明a b共线 小于0说明b到a为逆时针\n */\ndouble crossProduct(const point \u0026p1, const point \u0026p2,const point \u0026q1,const point \u0026q2){\n    return (p2.x-p1.x)*(q2.y-q1.y) - (p2.y-p1.y)*(q2.x-q1.x);\n}\n\n/**\n *判断点p是否在线段（q1,q2）上\n *判断点p是否在线段s上\n */\nint onSegment(const point \u0026p, const point \u0026q1, const point \u0026q2){\n    double rs = crossProduct(q1,p,q2,p);\n    if(complf(rs) == 0){\n        //共线\n        if(p.x \u003c= mymax(q1.x,q2.x) \u0026\u0026 p.x \u003e= mymin(q1.x,q2.x)\n        \u0026\u0026 p.y \u003c= mymax(q1.y,q2.y) \u0026\u0026 p.y \u003e= mymin(q1.y,q2.y)){\n            return 1;\n        }\n    }\n    return 0;\n}\nint onSegment(const point \u0026p,const segment \u0026s){\n    double rs  = crossProduct(s.a,p,s.b,p);\n    if(rs \u003e= 0 \u0026\u0026 rs \u003c eps){\n        if(p.x \u003c= mymax(s.a.x,s.b.x) \u0026\u0026 p.x \u003e= mymin(s.a.x,s.b.x)\n        \u0026\u0026 p.y \u003c= mymax(s.a.y,s.b.y) \u0026\u0026 p.y \u003e= mymin(s.a.y,s.b.y)){\n            return 1;\n        }\n    }\n    return 0;\n}\n\n/**\n *判断两线段是否相交\n */\nint intersect(const segment \u0026s1, const segment \u0026s2){\n    //先判断一条线段的端点是否在另外一条线段上\n    if(onSegment(s1.a,s2)\n    || onSegment(s1.b,s2)\n    || onSegment(s2.a,s1)\n    || onSegment(s2.b,s1)){\n        //\n        return 1;\n    }\n    //再判断线段的两个端点是否在另外一条线段的两侧\n    if(crossProduct(s1.a,s1.b,s1.a,s2.a)*crossProduct(s1.a,s1.b,s1.a,s2.b) \u003c 0\n    \u0026\u0026 crossProduct(s2.a,s2.b,s2.a,s1.a)*crossProduct(s2.a,s2.b,s2.a,s1.b) \u003c 0){\n        return 1;\n    }\n    return 0;\n```\n\n#### 35. 组合\n\n```c\n/**\n *组合 从a个数中选b个的选法C(a,b)\n */\nlong long combination( long long a,long long b )\n{\n    long long i,sum = 1;\n    if( a-b \u003c b ) b = a-b;\n    for( i = 0; i \u003c b; i++ ){\n        sum *= ( a - i ); sum/=i+1;\n    }\n    return sum;\n}\t\n```\n\n#### 36. Catalan Number\n\n```c\n/**\n *网上找的模板 验证过前一百的catalan数\n */\n#include\u003ciostream\u003e\n#include\u003cstring\u003e\n#include\u003ccstring\u003e\n#include\u003ciomanip\u003e\n#include\u003ccstdio\u003e\n#include\u003calgorithm\u003e\nusing namespace std;\n\n#define MAXN 9999\n#define DLEN 4\n\nclass BigNum{\nprivate:\n   int a[300];//DLEN digs for a position\n   int len;\npublic:\n   BigNum(){len = 1;memset(a,0,sizeof(a));}\n   BigNum(const int b);\n   BigNum(const BigNum \u0026 T);\n\n   bool     Bigger(const BigNum \u0026) const;\n   BigNum \u0026 operator=(const BigNum \u0026);\n   BigNum \u0026 Add(const BigNum \u0026);\n   BigNum \u0026 Sub(const BigNum \u0026);\n   BigNum operator+(const BigNum \u0026) const;\n   BigNum operator-(const BigNum \u0026) const;\n   BigNum operator*(const BigNum \u0026) const;\n   BigNum operator/(const int   \u0026) const;\n   void Print();\n};\nBigNum::BigNum(const int b)\n{\n   int c,d = b; len = 0;\n   memset(a,0,sizeof(a));\n   while(d \u003e MAXN){\n      c = d - d / (MAXN + 1) * (MAXN + 1);\n      d = d / (MAXN + 1);\n      a[len++] = c;\n   }a[len++] = d;\n\n}\nBigNum::BigNum(const BigNum \u0026 T) : len(T.len)\n{\n   int i; memset(a,0,sizeof(a));\n   for(i = 0 ; i \u003c len ; i++) a[i] = T.a[i];\n}\nbool  BigNum::Bigger(const BigNum \u0026 T) const\n{\n   int ln;\n   if(len \u003e T.len) return true;\n   else if(len == T.len){\n      ln = len - 1;\n      while(a[ln] == T.a[ln] \u0026\u0026 ln \u003e= 0) ln--;\n      if(ln \u003e= 0 \u0026\u0026 a[ln] \u003e T.a[ln]) return true;\n      else return false;\n   }\n   else return false;\n}\nBigNum \u0026 BigNum::operator=(const BigNum \u0026 n)\n{\n   len = n.len; memset(a,0,sizeof(a));\n   for(int i = 0 ; i \u003c len ; i++)\n      a[i] = n.a[i];\n   return *this;\n}\nBigNum \u0026 BigNum::Add(const BigNum \u0026 T)\n{\n   int i,big;\n   big = T.len \u003e len ? T.len : len;\n   for(i = 0 ; i \u003c big ; i++){\n\n      a[i] = a[i] + T.a[i];\n      if(a[i] \u003e MAXN){\n         a[i + 1]++;\n         a[i] = a[i] - MAXN - 1;\n      }\n   }\n   if(a[big] != 0) len = big + 1;\n   else len = big;\n   return *this;\n}\nBigNum \u0026 BigNum::Sub(const BigNum \u0026 T)\n{\n   int i,j,big;\n   big = T.len \u003e len ? T.len : len;\n   for(i = 0 ; i \u003c big ; i++){\n      if(a[i] \u003c T.a[i]){\n         j = i + 1;\n         while(a[j] == 0) j++;\n         a[j--]--;\n         while(j \u003e i) a[j--] += MAXN;\n         a[i] = a[i] + MAXN + 1 - T.a[i];\n      }\n      else a[i] -= T.a[i];\n   }\n   len = big;\n   while(a[len - 1] == 0 \u0026\u0026 len \u003e 1) len--;\n   return *this;\n}\nBigNum BigNum::operator+(const BigNum \u0026 n) const\n{\n   BigNum a = *this; a.Add(n);\n\n   return a;\n}\nBigNum BigNum::operator-(const BigNum \u0026 T) const\n{\n   BigNum b = *this;b.Sub(T);\n   return b;\n}\nBigNum BigNum::operator*(const BigNum \u0026 T) const\n{\n   BigNum ret;\n   int i,j,up;\n   int temp,temp1;\n\n   for(i = 0 ; i \u003c len ; i++){\n      up = 0;\n      for(j = 0 ; j \u003c T.len ; j++){\n         temp = a[i] * T.a[j] + ret.a[i + j] + up;\n         if(temp \u003e MAXN){\n            temp1 = temp - temp / (MAXN + 1) * (MAXN + 1);\n            up = temp / (MAXN + 1);\n            ret.a[i + j] = temp1;\n         }\n         else {\n            up = 0;\n            ret.a[i + j] = temp;\n         }\n      }\n      if(up != 0)\n         ret.a[i + j] = up;\n   }\n   ret.len = i + j;\n   while(ret.a[ret.len - 1] == 0 \u0026\u0026 ret.len \u003e 1) ret.len--;\n   return ret;\n}\nBigNum BigNum::operator/(const int \u0026 b) const\n{\n   BigNum ret;\n   int i,down = 0;\n\n   for(i = len - 1 ; i \u003e= 0 ; i--){\n      ret.a[i] = (a[i] + down * (MAXN + 1)) / b;\n      down = a[i] + down * (MAXN + 1) - ret.a[i] * b;\n   }\n   ret.len = len;\n   while(ret.a[ret.len - 1] == 0) ret.len--;\n   return ret;\n}\nvoid BigNum::Print()\n{\n   int i;\n   cout \u003c\u003c a[len - 1];\n   for(i = len - 2 ; i \u003e= 0 ; i--){\n      cout.width(DLEN);\n      cout.fill('0');\n      cout \u003c\u003c a[i];\n   }cout \u003c\u003c endl;\n   //输出的时候注意这里的换行,注意C++的输出不能和C和输出混用\n\n}\n\nint main(){\n     int i;\n     BigNum s[101]; s[1]=1;\n     for(i=1;i\u003c100;i++){\n      s[i+1]=BigNum(4*i+2)*(s[i])/(i+2);\n     }\n     while(scanf(\"%d\",\u0026i) \u0026\u0026 i != -1){\n         s[i].Print();\n     }\n    return 0;\n}\n```\n\n#### 37. 通项公式\n\n```c\n\n//F[n]=a*F[n-1]+b*F[n-2]的通项公式的求解\n//此类方程的特征方程为 x^2 - a^x - b*1 = 0;\n//假设方程的解为q1,q2 ; F[n]=c1 * q1^n + c2 * q2^n\n//将f[0] ,f[1]等已知的结果代入，就可求得c1,c2\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsongtianyi%2Facmer-qualification-code","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsongtianyi%2Facmer-qualification-code","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsongtianyi%2Facmer-qualification-code/lists"}