noip算法总结2016

合集下载

NOIP常用算法

NOIP常用算法

NOIP常用算法
NOIP是一种全球性的竞赛,考试内容涉及编程算法、数据结构、数
学建模等,其中算法题目占大多数。

这些算法可以根据其特点分为两类:
低效算法和高效算法。

一、低效算法
1、暴力解法
暴力解法是最简单的算法,就是直接枚举所有情况,找出最优解。


的运行时间是指数级别的,不推荐使用。

2、贪心算法
贪心算法是一种在每一步选择中都采取在当前状态下最好或最优(即
最有利)的选择,从而希望导致结果是最好或最优的算法。

贪心算法的时
间复杂度一般来说为O(n)。

3、分治法
分治法是将一个规模较大的问题分解为若干个规模较小的子问题,分
别解决,然后将子问题的解结合起来构成原问题的解。

它主要依赖于把一
个复杂的问题分解成两个或更多的相同或相似的子问题,然后递归求解,
分治法的时间复杂度可以达到O(nlogn)。

4、动态规划
动态规划是一种利用最优子结构性质解决复杂最优化问题的算法,通
过分解问题,将原问题转换为若干子问题,然后按照一些顺序求解子问题,利用子问题的解得到原问题的解,它的时间复杂度通常是O(n2)。

二、高效算法
1、算法
算法是指在一定的空间内,按照一定顺序最优解。

noip基本算法

noip基本算法

NOIP(全国青少年信息学奥林匹克竞赛)基本算法包括枚举、排序、二分答案、二分查找、贪心法、搜索算法、树上算法、图上算法、数据结构等。

具体来说,这些算法涵盖了基础算法的各个领域,例如枚举可以用于找出所有可能的解决方案,排序则可以用于对数据进行整理,二分答案和二分查找则是快速寻找目标值的有效方法,贪心法则可以用于解决一些最优解的问题,搜索算法则可以用于在大量可能的选择中找到最优解,树上算法则可以用于解决与树形结构相关的问题,图上算法则可以用于解决与图形相关的问题,而数据结构则可以用于高效地存储和操作数据。

在具体使用时,需要根据具体问题的需求选择合适的算法。

NOIP知识点总结

NOIP知识点总结

1时间复杂度
时间复杂度的分析方法
2排序算法
(1)平方排序算法(冒泡,插入,选择)
shell排序算法
(2)nlogn排序算法
快速排序(qsort,sort)
归并排序(求逆序对个数)
*
外部排序(堆排序)
3 数论
模运算
集合论
素数(Eratosthenes筛法)
进位制
欧几里德算法(辗转相除法)
扩展欧几里德算法(同余)ax + by = gcd(a,b)解线性同余方程ax ≡b(mod n)
*
中国剩余定理
高斯消元(线性代数)
4 数据结构
广度/ 宽度优先搜索及剪枝
表达式计算
Hash表
并查集
Tarjan算法(LCA最近公共祖先)
树状数组
*
线段树
5 动态规划(DP)
背包问题(背包九讲)
LIS(最长上升子序列)的二分优化
DP的队列优化(LCIS,单调队列)
区间的DP
树上的DP(记忆化搜索)
6 图论
单源最短路(dijkstra,floyd,spfa)
最小生成树(prim,kruskal)
拓扑排序
floyd求最小环
求图的强连通分量
判断图中是否有环
差分约束系统(就是求最长路,用spfa)
others:
指针(链表,搜索判重,邻接表,散列表,二叉树的表示,多叉树的表示)位运算
高精度的加减乘除开方(开方直接二分)
乘法转加法神器:log。

NOIP复习资料(算法部分)

NOIP复习资料(算法部分)

1、高精度·读入与输出用字符串读入数据,用数组存储数据。

为了便于计算,可以用数组下标为0的元素记录该高精度数的长度。

{说明部分}const maxn=250;type arr=array[0..maxn] of integer; var a,b:arr;{读入部分}procedure init(var a:arr);var str:string;i,j,l:integer;beginreadln(str);fillchar(a,sizeof(a),0);a[0]:=length(str);for i:=1 to a[0] doa[i]:=ord(str[a[0]-i+1])-ord(‘0’);end;{输出部分}procedure print(a:arr);var i:integer;beginfor i:=a[0] downto 1 dowrite(a[i]);writeln;end;{主程序部分}begininit(a);init(b);print(a);print(b);end.·高精度加法(1)A[i]+B[i]+进位得到和M;(2)M mod 10是结果的第i位数字;(3)M div 10 是该位向下一位的进位。

procedure add(var a:arr;b:arr);var m,i,j:integer;begin if a[0]<b[0] then a[0]:=b[0];m:=0;for i:=1 to a[0] dobeginm:=m+a[i]+b[i];a[i]:=m mod 10;m:=m div 10;end;if m>0 then begininc(a[0]);a[a[0]]:=m;end;end;·高精度减法procedure minus(var a:arr;b:arr;var p:integer);{a-b}var i,j,k,m:integer;temp:arr;beginif a[0]>b[0] then p:=1else if a[0]<b[0] then p:=-1elsebegink:=a[0];while (a[k]=b[k]) and (k>0) do dec(k);if a[k]<b[k] then p:=-1;end;if p<0 thenbegintemp:=a;a:=b;b:=temp;end;for i:=1 to a[0] dobegina[i]:=a[i]-b[i];if a[i]<0 thenbegindec(a[i+1]);inc(a[i],10);end;end;k:=a[0];while (a[k]=0) and (k>1) do dec(k); a[0]:=k;end;·高精度减法(by yym大牛)if (length(n1)<length(n2)) or (length(n1)=length(n2)) and (n1<n2) thenbeginn:=n1;n1:=n2;n2:=n;write('-');end;lena:=length(n1);lenb:=length(n2);for i:=1 to lena do a[lena-i+1]:=ord(n1[i])-ord('0');for i:=1 to lenb do b[lenb-i+1]:=ord(n2[i])-ord('0');i:=1;while (i<=lena) or(i<=lenb) dobeginx:=a[i]-b[i]+10+x;c[i]:=x mod 10;x:=x div 10-1;i:=i+1;end;lenc:=i;while (c[lenc]=0) and (lenc>1) do dec(lenc);·高精度乘法(1)高精度乘以单精度procedure multi1( var a:arr;x:integer); var i,m:integer;beginm:=0;for i:=1 to a[0] dobegininc(m,a[i]*x);a[i]:=m mod 10;m:=m div 10; end;while m<>0 dobegininc(a[0]);a[a[0]]:=m mod 10;m:=m div 10;end;end;(2)高精度乘以高精度procedure multi2(var a:arr;b:arr); var c:arr;i,j,k,l:integer;beginfillchar(c,sizeof(c),0);for i:=1 to a[0] dofor j:=1 to b[0] doinc(c[i+j-1],a[i]*b[j]);for i:=1 to maxn-1 dobegininc(c[i+1],c[i] div 10);c[i]:=c[i] mod 10;end;k:=maxn;while (c[k]=0) and (k>1) dodec(k);c[0]:=k;a:=c;end;2、位运算运算符优先级Not 1(高)*,/,div,mod,and,shl,shr 2Xor,+,-,or 3In,=,<,>,>=,<=,<> 4(低)not 取反not(1)=0; not(0)=1;and 同真则真1 and 1=1; 0and 1=0; 0 and 0=0;or 有真则真1 and 1=1; 0 and 1=1; 0 and 0=0;xor 异真同假1 and 1=0; 0 and 1=1 0 and 0=0;shl a shl b就表示把a转为二进制后左移b位(在后面添b个0)。

NOIP算法总结与复习

NOIP算法总结与复习

NOIP算法总结与复习NOIP算法总结与复习(看了看李总的蓝⽪书,收获颇多,记下此⽂,以明志~~)(⼀)数论1、最⼤公约数,最⼩公倍数2、筛法球素数3、mod规律公式4、排列组合数,错排5、Catalan数6、康托展开7、负进制8、中位数的应⽤9、位运算(⼆)⾼精度算法1、朴素加法减法2、亿进制加法减法3、乘法4、除法5、亿进制读⼊处理6、综合运⽤(三)排序算法1、冒泡2、快排3、堆排4、归并(四)DP1、概念2、解题步骤3、背包类dp4、线性dp5、区间动态规划6、坐标型动态规划(规则类dp)7、资源分配型动态规划8、树型动态规划9、状态压缩的动态规划10、动态规划的⼀般优化⽅法(五)图论1、Floyd-Warshall2、Bellman-ford3、SPFA4、dijkstra5、prim6、kruskal7、欧拉回路8、哈密顿环9、flood fill(求图的强联通分量)10、最⼩环问题11、Topological sort12、次短路13、次⼩⽣成树(六)树1、堆2、⼆叉排序树3、最优⼆叉树(哈夫曼树)4、求树的后序遍历5、并查集及应⽤(七)分治1、⼆分查找2、⼆分逼近(注意精度问题)3、⼆分答案4、快排(见排序算法)5、归并排序(见排序算法)6、快速幂(⼋)贪⼼(九)搜索(⼗)其它1、离散化2、KMP3、字符串哈希4、常⽤字符串函数过程。

noip2016普及组解题报告

noip2016普及组解题报告

买铅笔【题目描述】P老师需要去商店买n支铅笔作为小朋友们参加NOIP的礼物。

她发现商店一共有 3种包装的铅笔,不同包装内的铅笔数量有可能不同,价格也有可能不同。

为了公平起见,P老师决定只买同一种包装的铅笔。

商店不允许将铅笔的包装拆开,因此P老师可能需要购买超过n支铅笔才够给小朋友们发礼物。

现在P老师想知道,在商店每种包装的数量都足够的情况下,要买够至少n 支铅笔最少需要花费多少钱。

【输入格式】输入的第一行包含一个正整数n,表示需要的铅笔数量。

接下来三行,每行用两个正整数描述一种包装的铅笔:其中第一个整数表示这种包装内铅笔的数量,第二个整数表示这种包装的价格。

保证所有的7个数都是不超过10000的正整数。

【输出格式】输出一行一个整数,表示P老师最少需要花费的钱。

【样例输入】572 250 3030 27【样例输出】54【算法分析】水题,整除、取余。

【AC代码】varn,i,a,b,p,ans:longint; beginreadln(n);ans:=maxlongint;for i:=1 to 3 dobeginread(a,b);if (n mod a)<>0 then p:=(n div a +1)*belsep:=(n div a)*b;if p<ans then ans:=p; end;writeln(ans);end.回文日期【题目描述】在日常生活中,通过年、月、日这三个要素可以表示出一个唯一确定的日期。

牛牛习惯用8位数字表示一个日期,其中,前4位代表年份,接下来2位代表月份,最后2位代表日期。

显然:一个日期只有一种表示方法,而两个不同的日期的表示方法不会相同。

牛牛认为,一个日期是回文的,当且仅当表示这个日期的8位数字是回文的。

现在,牛牛想知道:在他指定的两个日期之间包含这两个日期本身),有多少个真实存在的日期是回文的。

一个8位数字是回文的,当且仅当对于所有的i ( 1 <=i<= 8 )从左向右数的第i 个数字和第9-i个数字(即从右向左数的第i个数字)是相同的。

Noip算法总结

Noip算法总结
第二题超难(我觉得。。)
大致应该拿280左右
Noip_01_p
1数的计数
2最大公约数最小公倍数
3求先序排列
4装箱问题
总结
方法:dfs即可
难度:*
方法:分解质因数+乘法原理
难度:*
方法:递归+字符串处理
难度:*
方法:动态规划
难度:*
本套题目拿满分不难
Noip_02_p
1级数求和
2选数
3产生数
4过河卒
总结
难度:*
方法:用链表模拟增删和替换操作即可
难度:*
方法:构造+递归
根据邻接矩阵的对称性
(详见附图1)
难度:**
第四题不好想,其他没什么,应该考到300+吧。
Noip_97_p
1方格棋盘
2三角形枚举
3街道走向
总结
方法:枚举矩形(正方形)的大小然后直接算。
难度:*
备注:第4组数据有误
应改为:
输入:20 20
5灯的排列
第一问直接dfs出一种排列的所有方案。
第二问将第一问的方案数乘上颜色数的阶乘
难度:
**
Noip_96_p
1乘法运算
2横竖斜格子
3字符串编辑
4比赛安排
总结
方法:高精度/模拟
注意到范围在100以内。
直接用int读入,每一位拆出来乘一下,做个样子就可以了。
难度:*
方法:直接算
或许纯粹考察的while语句。
(本题数据规模模拟即可)
难度:*
方法:动态规划
难度:*
方法:递推+高精度
难度:***
前三题基本上是送分,第四题较难ቤተ መጻሕፍቲ ባይዱ理应拿310分或更高。

NOIP算法整理

NOIP算法整理

目录搜索 (4)DFS (4)框架 (4)优化 (4)BFS (4)框架 (4)优化 (5)排序 (5)冒泡排序 (5)选择排序 (5)插入排序 (6)桶排序 (6)快速排序 (7)堆排序 (7)数学定理 (8)中国剩余定理 (8)康托展开 (9)错排通项 (9)费马大定理 (9)费马小定理 (9)逆元 (9)欧拉函数 (10)Stirling数 (10)Stirling's approximation (10)数论 (11)GCD&LCM (11)素数 (11)快速幂 (12)模运算法则 (13)组合和全排列 (13)阶乘 (13)约瑟夫环问题 (13)Catalan数 (14)扩展欧几里德算法 (15)对自然数因子的计算 (15)矩阵乘法 (16)位运算 (16)动态规划 (18)步骤 (18)关键 (19)格式 (19)推荐参考资料 (19)推荐习题 (20)图论算法 (20)回路问题 (20)Euler回路 (20)Hamilton回路 (20)一笔画问题 (20)图的遍历 (23)DFS (23)BFS (23)最短路径 (25)dijkstra算法 (25)floyd算法 (26)spfa算法 (27)最小生成树 (29)prim算法 (29)Kruskal算法 (31)topology排序 (32)关键路径 (33)利用拓扑排序 (33)按照概念 (35)次短路 (36)次小生成树 (36)匈牙利算法 (37)博弈 (38)取对称状态 (38)取NIM值 (38)分治 (39)回溯 (41)N皇后 (41)Hanoi Tower (41)高精度计算 (42)高精度加法 (42)高精度减法 (42)高精度乘法 (44)高精度阶乘 (48)高级数据结构 (49)二叉树 (49)并查集 (51)树状数组 (52)线段树 (52)二叉搜索树 (54)进制转换 (59)1.将m进制数n转化成一个十进制数 (59)2.将十进制数n转换成m进制数 (59)搜索DFS框架procedure dfs(x);varbeginif达到目标状态then输出结果并退出过程;if满足剪枝条件then exit;for i:=1to搜索宽度dobegin备份现场;(注意如果现场使用了全局变量,则需要使用局部变量备份)dfs(参数+增量);恢复现场;end;优化(1)最优化剪枝:求最优值时,当前的状态无论如何不可能比最优值更优,则退出,可与展望结合剪枝(2)可行性剪枝:提前判断该状态是否能得到可行解,如不能则退出(3)记忆化搜索:对于已经搜索过的状态直接退出(4)改变搜索顺序:对于看起来希望更大的决策先进行搜索(5)优化搜索策略(6)预处理找到大体搜索翻译(7)改写成IDA*算法(8)卡时(注意现在联赛中禁止使用meml掐时)BFS框架初始化;把初始布局存入设首指针head=0;尾指针tail:=1;repeatinc(head),取出队列首记录为当前被扩展结点;for i:=1to规则数do{r是规则编号}beginif新空格位置合法thenbeginif新布局与队列中原有记录不重复tail增1,并把新布局存入队尾;if达到目标then输出并退出;end;end;until head>=tail;{队列空}优化判重的优化:hash,二叉排序树双向广搜或启发式搜索改写成A*算法二分优化排序冒泡排序var a:array[1..100] of longint;t,n,i,j:longint; procedure sort;beginfor i:=1to n-1do{与每个数都进行比较}for j:=1to n-i doif a[j]>a[j+1] thenbegint:=a[j];a[j]:=a[j+1];a[j+1]:=t;end;end;选择排序var a:array[1..100] of longint;t,n,i,j:longint;procedure sort;beginfor i:=1to n-1dofor j:=1+i to n do{大数沉小数浮}if a[j]>a[i] thenbegint:=a[j];a[j]:=a[i];a[i]:=t;end;end;插入排序var a:array[0..100] of longint;n,i,j,t:longint;procedure sort;beginfor i:=2to n dofor j:=1to (i-1) dobeginif (a[i]<a[j]) thenbegint:=a[j];a[j]:=a[i];a[i]:=t;end;end;end;桶排序var a,b:array[0..100] of longint;r,i,j,t,k,n:longint; procedure sort;beginfor i:=0to100do b[i]:=0;{为B数组清零,小桶内容清零} for i:=1to n do b[a[i]]:=b[a[i]]+1;{桶的序号就是那个要排序的东西;出现一次,桶里得旗数加一} for i:=0to100do{扫描所有的桶}beginif b[i]<>0then{桶里有旗}for j:=1to b[i] do write(i,'');{桶的序号就是那个数} end;end;快速排序var a:array[1..100] of longint;n,i,h,g:longint;procedure kp(l,r:longint);{变量不能与全局变量相同,否则会被抹去} var b,m,i,j,t:longint;begini:=l;j:=r;m:=a[(l+r) div2];{基准数最好从中间取}repeatwhile a[j]>m do dec(j);while a[i]<m do inc(i);{两侧的哨兵移动}if i<=j then{哨兵未碰面}{“=”利用repeat循环的性质,使repeat循环得以结束} begint:=a[j];a[j]:=a[ia[i]:=t;{交换两个哨兵的值}inc(j);dec(j);{哨兵继续运动}end;until i>j;if j>l then kp(l,j);if i<r then kp(i,r);{都是循环不结束后进行的动作}end;beginread(n);for i:=1to n do read(a[i]);kp(1,n); {“一”位置与“N”位置}for i:=1to n-1do write(a[i],'');write(a[n]);{防止多输出空格使程序结果出错}end.堆排序var a:array[1..100] of longint;n,i,b:longint;procedure jianshu(i:longint);beginwhile ((a[i]>a[i*2])or(a[i]>a[i*2+1]))and(i<=n div2) do{当父亲数大于子女数时并且他有孩子时进行}beginif a[i*2]<=a[i*2+1]{左儿子小于右儿子}thenbeginb:=a[i*2]; a[i*2]:=a[i];a[i]:=b;{左右儿子的值互换}jianshu(i*2);{继续为左儿子建树}endelsebeginb:=a[i*2+1];a[i*2+1]:=a[i];a[i]:=b;jianshu(i*2+1);{上同,不过是为右儿子建树}end;end;end;procedure tiao;beginwhile n<>0dobeginwrite(a[1]);a[1]:=a[n];n:=n-1;for i:=(n div2) downto1dojianshu(i);end;end;beginread(n);for i:=1to n doread(a[i]);for i:=(n div2) downto1dojianshu(i);tiao;end.数学定理中国剩余定理若有一些两两互质的整数m1, m2,… mn,则对任意的整数:a1,a2,...an,以下联立同余方程组对模数m1, m2,… mn 有公解:康托展开a[i]为当前未出现的元素中是排在第几个(从0开始)把一个整数X展开成如下形式:X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[2]*1!+a[1]*0!其中a[i]为当前未出现的元素中是排在第几个(从0开始),并且0<=a[i]<i(1<=i<=n)错排通项考虑一个有n个元素的排列,若一个排列中所有的元素都不在自己原来的位置上,那么这样的排列就称为原排列的一个错排。

NOI及NOIP需要知道的与自己的心得

NOI及NOIP需要知道的与自己的心得

一、(搜索)双向广度搜索广度搜索虽然可以得到最优解,但是其空间消耗增长太快。

但如果从正反两个方向进行广度搜索,理想情况下可以减少二分之一的搜索量,从而提高搜索速度。

范例:有N个黑白棋子排成一派,中间任意两个位置有两个连续的空格。

每次空格可以与序列中的某两个棋子交换位置,且两子的次序不变。

要求出入长度为length的一个初始状态和一个目标状态,求出最少的转化步数。

问题分析:该题要求求出最少的转化步数,但如果直接使用广度搜索,很容易产生数据溢出。

但如果从初始状态和目标状态两个方向同时进行扩展,如果两棵解答树在某个节点第一次发生重合,则该节点所连接的两条路径所拼成的路径就是最优解。

对广度搜索算法的改进:1。

添加一张节点表,作为反向扩展表。

2。

在while循环体中在正向扩展代码后加入反向扩展代码,其扩展过程不能与正向过程共享一个for循环。

3。

在正向扩展出一个节点后,需在反向表中查找是否有重合节点。

反向扩展时与之相同。

对双向广度搜索算法的改进:略微修改一下控制结构,每次while循环时只扩展正反两个方向中节点数目较少的一个,可以使两边的发展速度保持一定的平衡,从而减少总扩展节点的个数,加快搜索速度。

二、(搜索)分支定界分支定界实际上是A*算法的一种雏形,其对于每个扩展出来的节点给出一个预期值,如果这个预期值不如当前已经搜索出来的结果好的话,则将这个节点(包括其子节点)从解答树中删去,从而达到加快搜索速度的目的。

范例:在一个商店中购物,设第I种商品的价格为Ci。

但商店提供一种折扣,即给出一组商品的组合,如果一次性购买了这一组商品,则可以享受较优惠的价格。

现在给出一张购买清单和商店所提供的折扣清单,要求利用这些折扣,使所付款最少。

问题分析:显然,折扣使用的顺序与最终结果无关,所以可以先将所有的折扣按折扣率从大到小排序,然后采用回溯法的控制结构,对每个折扣从其最大可能使用次数向零递减搜索,设A为以打完折扣后优惠的价格,C为当前未打折扣的商品零售价之和,则其预期值为A+a*C,其中a为下一个折扣的折扣率。

NOIP算法整理

NOIP算法整理

前言
离NOIP还有一个星期,匆忙的把寒假整理的算法补充完善,看着当时的整理觉得那时还年少。

第二页贴了几张从贴吧里找来的图片,看着就很热血的。

旁边的同学都劝我不要再放PASCAL 啊什么的了,毕竟我们的下一级直接学C++。

即便我本人对C++也是赞赏有加,不过PASCAL 作为梦的开始终究不能忘记。

不像机房中其余的OIERS,我以后并不想学计算机类的专业。

当年来学这个竞赛就是为了兴趣,感受计算机之美的。

经过时迁,计划赶不上变化,现在尚处于迷茫之中,也很难说当时做的决定是对是错。

然而我一直坚信迷茫的时候选择难走的路会看见更好的风景。

这篇文章简单的说了一下NOIP考试中会常用的算法,可能难度掌握的不是太好,有一部分内容不是NOIP考查范围,然而随着难度的增加,看一些更高级的算法也没有坏处。

还有一些非常非常基础的比如链表啊什么的就直接没有写上(别问我为什么整理了那么多的排序算法)。

最后祝大家在NOIP中取得理想的成绩!
NOIP算法总结 1 山东省广饶一中杨庆礼。

NOIP2016提高组初赛解析

NOIP2016提高组初赛解析

一、单项选择题1.这题不是zz都能选对。

2.不难看出按键的顺序是五个一循环,于是可以求出共有多少个循环,进而求出按了多少次CapsLock,最后就可以得出答案。

3.异或就是按位运算,相同取1,不同取0,知道了这个就很容易得出答案。

4.把二进制数0.1先转成十进制,再转成八进制。

5.以第一个数为基准,依次比较后面的N-1个数即可。

6.画出中缀表达式的树型图,求其后序遍历即可。

7.把每一个叶子结点和只有一个孩子的结点算一下就行。

8.根据公式(8-1)*8/2得到28条边,然后增加一个节点使其成为非连通图。

9.计算机硬件知识(说实话考试的时候并不会,但是看到一堆选B的就蒙了B结果蒙对了)。

10.手动模拟就行。

11.也是手动模拟,注意形如(1,2,4)和(4,2,1)算同一种方法。

12.就是找图中没有与Jacob连线的人。

13.手动模拟。

14.即使不会使用主定理,也可以列举一些特殊数值,并根据O() 记号的含义得出答案。

15.第一个空表示第k个数就是峰顶,第二个空表示峰顶在[k+1,n],第三个空表示峰顶在[1,k-1],理解程序就不难做对。

二、不定项选择题1.计算机基础知识。

2.即使你不知道网络接入通讯设备是什么也可以做出来,毕竟光驱、鼠标、显卡和网络从名字上看都没有半毛钱关系。

3.太简单不解释,做错的回去再学几年去吧。

4.看懂图就行,这题完全是模拟,把四个选项都模拟一下就行。

5.不解释。

如果你选了U盘,那你不如把直接你教练带去帮你得了。

三、问题求解1.很简单的斐波那契数列。

考试的时候我就是把1*1到1*5的方格都模拟一下,规律就不难找到了。

考试结束后我思考了一下,设f[n]表示1*n的满足条件的方格的数量,则当前格只有两个选择:涂白或图黑。

第i个格子只和第i-1个格子有关系,所以如果第n个格子涂白,那么第n-1个格子怎么涂都行,如果第n个格子涂黑,那么第n-1个格子只能涂白,但是第n-2个格子可以任意涂,所以f[n]=f[n-1]+f[n-2]。

Noip常用算法大全

Noip常用算法大全

Noip常用算法大全一、数论算法1.求两数的最大公约数function gcd(a,b:integer):integer;beginif b=0 then gcd:=aelse gcd:=gcd (b,a mod b);end ;2.求两数的最小公倍数function lcm(a,b:integer):integer;beginif a<b then swap(a,b);lcm:=a;while lcm mod b>0 do inc(lcm,a);end;3.素数的求法A.小范围内判断一个数是否为质数:function prime (n: integer): Boolean;var I: integer;beginfor I:=2 to trunc(sqrt(n)) doif n mod I=0 then beginprime:=false; exit;end;prime:=true;end;B.判断longint范围内的数是否为素数(包含求50000以内的素数表):procedure getprime;vari,j:longint;p:array[1..50000] of boolean;beginfillchar(p,sizeof(p),true);p[1]:=false;i:=2;while i<50000 do beginif p[i] thenbeginj:=i*2;while j<50000 dobegin {筛选法}p[j]:=false;inc(j,i);end;end;inc(i);end;l:=0;for i:=1 to 50000 doif p[i] then begininc(l);pr[l]:=i;end;end;{getprime}function prime(x:longint):boolean;var i:integer;beginprime:=false;for i:=1 to l doif pr[i]>=x then breakelse if x mod pr[i]=0 then exit;prime:=true;end;{prime}二、图论算法1.最小生成树A.Prim算法:procedure prim(v0:integer);varlowcost,closest:array[1..maxn] of integer;i,j,k,min:integer;beginfor i:=1 to n do beginlowcost:=cost[v0,i];closest:=v0;end;for i:=1 to n-1 do begin{寻找离生成树最近的未加入顶点k}min:=maxlongint;for j:=1 to n doif (lowcost[j]<min) and (lowcost[j]<>0) then beginmin:=lowcost[j];k:=j;end;lowcost[k]:=0; {将顶点k加入生成树}{生成树中增加一条新的边k到closest[k]}{修正各点的lowcost和closest值}for j:=1 to n doif cost[k,j]<lwocost[j] then beginlowcost[j]:=cost[k,j];closest[j]:=k;end;end;end;{prim}B.Kruskal算法:(贪心)按权值递增顺序删去图中的边,若不形成回路则将此边加入最小生成树。

NOIP算法分类总结(C语言)

NOIP算法分类总结(C语言)

模块目录一、排序1.选择排序2.插入排序3.冒泡排序4.快速排序5.堆排序6.归并排序7.线性时间排序二、高精度1.高精度比较2.高精度加法3.高精度减法4.单精度乘法5.高精度乘法6.单精度除法7.高精度除法8.进制转换三、数论1.欧几里德算法2.扩展欧几里德3.求最小公倍数4.求解线形同余方程5.素数的判断6.素数的生成四、排列组合1.排列生成算法2.组合生成算法3.排列按序生成法4.排列字典序生成法五、图论1.图的读入2.深度优先搜索3.广度优先搜索4.强连同分量5.拓扑排序6.最小生成树7.最短路径六、背包问题1.装满背包2.一维价值最大背包3.二位价值最大背包Part1.数学有关1.最大公约数Long gcd(long x,long y){return x%y==0?y:gcd(y,x%y);}2.最小公倍数Long lcm(long x,long y){return x*y/gcd(x,y);}3.判断素数Bool prime(long p){long x=sqrt(p)+1;If(p==1||p==2||p==3)return true;If(p%2==0||p%3==0)return false;For(int i=5;i<=x;i+=2)If(p%i==0)return false;Return true;}4.暴力分解质因数Int record[10000];Void Baoli(long p){Long x=sqrt(p)+1,i,lc=0,ok=true;If(prime(p)==1){Lc=1; record[lc]=p;Return;}for(i=2;(i<=x)&&ok;i++){While(p%i==0){lc++;Record[lc]=i;P/=i;If(p==1){ok=false;Break;}}}}5.卡特兰数long f[1001]={0};long CountCatalan(long n){f[0]=f[1]=1;for(long i=1;i<=n;i++){f[i]=0;for(long j=1;j<=i;j++)f[i]+=f[i-j]*f[j-1];}return f[n];}Part2.排序相关1.快排Void QuickSort(int *A,int p1,int p2){If(p1>=p2)return;Int x=A[(p1+p2)>>1],i=p1,j=p2;While(i<j){while(A[i]<x)i++;While(A[j]>x)j--;If(i<=j){Int Temp=A[i];A[i]=A[j];A[j]=Temp;i++; j--;}}QuickSort(A,p1,j);QuickSort(A,i,p2);}2.冒泡排序Void BubbleSort(int *A,int n){Int temp;For(int i=1;i<n;i++)For(int j=i;j<=n;j++)If(a[j-1]>a[j])temp=a[j-1],a[j-1]=a[j],a[j]=temp; }3.堆排序Void MinHeapify(int p,const int HeapSize){ Int Small=p;If(p*2<=HeapSize&&a[p*2]<a[Small])Small=p*2;If(p*2+1<=Heapsize&&a[p*2+1]<a[Small])Small=p*2+1;If(Small!=p){Int temp=a[p];a[p]=a[small];a[small]=temp;MinHeapify(small,HeapSize);}}void ExtraMin(int &HeapSize){Int ans=a[1];a[1]=a[HeapSize];A[HeapSize--]=ans;MinHeapify(1);}Void Heapsort(int n){HeapSize=n;For(int i=n/2;i>=1;i--)MinHeapify(i,HeapSize);For(int i=1;i<=n;i++)ExtraMin(HeapSize);}Part3.图论相关1.最小生成树prim算法Const int maxint=(1<<16)-1;Int g[][],dis[],n,visit[];int Prim(){int mst=0;Int dex=1,temp=-1;For(int i=1;i<=n;i++)dis[i]=maxint;Dis[dex]=0;For(int i=1;i<=n-1;i++){Visit[dex]=1;For(int j=1;j<=n;j++){If(visit[j]==0){If(g[dex][j]!=0&&g[dex][j]<dis[j])dis[j]=g[dex][j];If(temp==-1||dis[j]<dis[temp])temp=j;}}dex=temp;mst+=dis[dex];}Return mst;}//O(n^2)2.最小生成树prim算法利用最小堆优化且图用邻接表存储const long maxint=(1<<30-1);struct Hnode{long dis,v;Hnode(){v=0;dis=maxint;}};struct Gnode{long v,w,pos,In;struct Gnode *next;Gnode(){next=NULL;v=w=In=pos=0;}}G[2001];long n,m,vis[2001]={0};long x,y,z;class HeapClass{public:Hnode A[2001];long Size;void MinHeapify(long dep){long Small=dep;struct Hnode Temp;if(2*dep<=Size&&A[Small].dis>A[2*dep].dis)Small=2*dep;if(2*dep+1<=Size&&A[Small].dis>A[2*dep+1].dis)Small=2*dep+1;if(Small!=dep){Temp=A[Small];A[Small]=A[dep];A[dep]=Temp;G[A[dep].v].pos=dep;G[A[Small].v].pos=Small;MinHeapify(Small);}}struct Hnode ExtraMin(){struct Hnode Ans=A[1];A[1]=A[Size--];G[A[Size+1].v].pos=Size+1;G[A[1].v].pos=1;MinHeapify(1);return Ans;}void Decrease(long dep){Hnode x=A[dep];long i;while(dep>1){i=dep/2;if(A[i].dis<=x.dis)break;A[dep]=A[i],G[A[dep].v].pos=dep;dep=i;}A[dep]=x;G[A[dep].v].pos=dep;}}Heap;long Prim(){long MST=0;Heap.A[1].v=1;Heap.A[1].dis=0;G[1].pos=1;for(int i=2;i<=n;i++){Heap.A[i].v=i;G[i].pos=i;}for(i=n/2;i>=1;i--)Heap.MinHeapify(i);for(int k=1;k<=n;k++){Hnode Now=Heap.ExtraMin();MST+=Now.dis;G[Now.v].pos=-1;Gnode *T=G[Now.v].next;while(T){if((G[T->v].pos!=-1)&&((T->w)<(Heap.A[G[T->v].pos].dis) )){Heap.A[G[T->v].pos].dis=T->w;Heap.Decrease(G[T->v].pos);}T=T->next;}}Retrun MST;}//O(nlogn)3.最小生成树kruskal算法利用并查集(的路径压缩)优化int f[],m,n; //m表示边数,n表示节点数Struct Edge{Int x,y,w;}E[100000],Temp,P;Int find(int x){If(f[x]!=x)f[x]=find(f[x]);Return f[x];}//并查集的性价比多高啊。

冲刺NOIp2016算法模板(C++)

冲刺NOIp2016算法模板(C++)

冲刺NOIp2016算法模板(C++)Catalogue:•冲刺NOIp2016算法模板o数据结构▪栈▪队列▪树状数组▪单调队列o STL▪Vector▪Queue▪Priority_queue▪Stack▪Deque▪Bitset▪Set▪Multiset▪Map▪Algorithm里其他好用的函数▪Next_permutation▪Lower_bound与Upper_bound▪Merge▪sort▪Reverse▪Unique▪Random_shuffleo数论▪快速幂▪普通快速幂▪矩阵快速幂▪筛法求素数▪欧拉筛法▪验证素数▪普通方法▪Miller-Rabin▪分解质因数唯一分解定理▪最大公约数和最小公倍数▪扩展欧几里德▪逆元▪Catalan数o高精▪读入储存与输出▪高精度加法▪高精加单精▪高精加高精▪高精度乘法▪高精乘单精▪高精乘高精▪高精度除法▪高精度除以单精度▪压位o图论▪最短路▪SPFA▪次短路▪最小生成树MST▪Kruskal▪图的遍历▪Floyed▪二分图染色o树▪建树▪传递闭包▪并查集▪LCAo动态规划▪线性DP▪最大递增子序列和▪最大连续子序列和▪最长公共自序列和▪字符串转换问题▪最长不下降子序列▪背包DP▪01背包▪完全背包▪混合背包▪分组背包o其他模板▪归并排序▪二分▪Hash数据结构栈int strack[maxn];int head;bool b[maxn];void push(int x) {strack[++head]=x; b[x]=true;};int pop(){int ret;ret=strack[head--]; b[ret]=false; return ret;};bool empty(){return head>0;}•1•2•3•4•5•6•7•8•9•10•11•12•13•14•15•16•17•18•19•20•21•22队列int queue[2*maxn];int tail,head;bool b[maxn];void push(int x){queue[++tail]=x;bool[x]=true;};int pop(){int ret;ret=queue[++head];b[ret]=false;return ret;};bool empty(){return head>=tail;};•1•2•3•4•5•6•7•8•9•10•11•12•13•14•15•16•17•18•19•20•21•22当然有的时候你手写的数据结构需要比较大的空间,这样队列就会造成很多损失,所以相应的就有两种解决方法:一:STL;二:循环队列,只需改两个地方(代码如下);head=(head+1)%n+1;//把head++改tail=(tail+1)%n+1;//把tail++改•1•2树状数组int lowbit(int x){return x&-x;};int getsum(int n) //求1~n见的和{int ret=0;while(n){ret+=c[n];n-=lowbit(n);};return ret;};void add(int n,int x) //给a[n]加上x{a[n]+=x;while(n<=maxn){c[n]+=x;n+=lowbit(n);•1•2•3•4•5•6•7•8•9•10•11•12•13•14•15•16•17•18•19•20•21•22•23应用模型:•树状数组求逆序对:void update(int n) {while(n<=maxn) {c[n]+=1;n+=lowbit(n); };};for(int i = 1; i <= n; ++i) //主程序里面加上这个{update(reflect[i]);ans += i - getsum(reflect[i]);//reflect是离散化后的数组}•1•2•3•4•5•6•7•8•9•10•11•12•13•14单调队列•例题:Luogu P1823 音乐会的等待(我写了一篇此题的解题报告)以下单调队列的标程就用的音乐会的等待的。

历届NOIp动态规划梳理..

历届NOIp动态规划梳理..

Sample Problem3
拦截导弹(NOIp1999)
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦 截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发 炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统 还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。 输入导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数), 计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种 导弹拦截系统。 样例: INPUT 389 207 155 300 299 170 158 65 统数)
同样三取方格数只要f[x,i,j,k]用同样的方法即可。
Sample Problem7
传纸条(NOIp2008)
【问题描述】 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题。一 次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被 安排在矩阵对角线的两端,因此,他们就无法直接交谈了。幸运的是,他们 可以通过传纸条来进行交流。纸条要经由许多同学传到对方手里,小渊坐在 矩阵的左上角,坐标(1,1),小轩坐在矩阵的右下角,坐标(m,n)。从小渊传到 小轩的纸条只可以向下或者向右传递,从小轩传给小渊的纸条只可以向上或 者向左传递。 在活动进行中,小渊希望给小轩传递一张纸条,同时希望小轩给他回复。 班里每个同学都可以帮他们传递,但只会帮他们一次,也就是说如果此人在 小渊递给小轩纸条的时候帮忙,那么在小轩递给小渊的时候就不会再帮忙。 反之亦然。 还有一件事情需要注意,全班每个同学愿意帮忙的好感度有高有低(注 意:小渊和小轩的好心程度没有定义,输入时用0表示),可以用一个0-100的 自然数来表示,数越大表示越好心。小渊和小轩希望尽可能找好心程度高 的同学来帮忙传纸条,即找到来回两条传递路径,使得这两条路径上同学 的好心程度只和最大。现在,请你帮助小渊和小轩找到这样的两条路径。

noip2016普及组解题报告

noip2016普及组解题报告

买铅笔【题目描述】P老师需要去商店买n支铅笔作为小朋友们参加NOIP的礼物。

她发现商店一共有 3种包装的铅笔,不同包装内的铅笔数量有可能不同,价格也有可能不同。

为了公平起见,P老师决定只买同一种包装的铅笔。

商店不允许将铅笔的包装拆开,因此P老师可能需要购买超过n支铅笔才够给小朋友们发礼物。

现在P老师想知道,在商店每种包装的数量都足够的情况下,要买够至少n 支铅笔最少需要花费多少钱。

【输入格式】输入的第一行包含一个正整数n,表示需要的铅笔数量。

接下来三行,每行用两个正整数描述一种包装的铅笔:其中第一个整数表示这种包装内铅笔的数量,第二个整数表示这种包装的价格。

保证所有的7个数都是不超过10000的正整数。

【输出格式】输出一行一个整数,表示P老师最少需要花费的钱。

【样例输入】572 250 3030 27【样例输出】54【算法分析】水题,整除、取余。

【AC代码】varn,i,a,b,p,ans:longint; beginreadln(n);ans:=maxlongint;for i:=1 to 3 dobeginread(a,b);if (n mod a)<>0 then p:=(n div a +1)*belsep:=(n div a)*b;if p<ans then ans:=p; end;writeln(ans);end.回文日期【题目描述】在日常生活中,通过年、月、日这三个要素可以表示出一个唯一确定的日期。

牛牛习惯用8位数字表示一个日期,其中,前4位代表年份,接下来2位代表月份,最后2位代表日期。

显然:一个日期只有一种表示方法,而两个不同的日期的表示方法不会相同。

牛牛认为,一个日期是回文的,当且仅当表示这个日期的8位数字是回文的。

现在,牛牛想知道:在他指定的两个日期之间包含这两个日期本身),有多少个真实存在的日期是回文的。

一个8位数字是回文的,当且仅当对于所有的i ( 1 <=i<= 8 )从左向右数的第i 个数字和第9-i个数字(即从右向左数的第i个数字)是相同的。

noip算法总结2016

noip算法总结2016

算法总结一、动态规划和递推dp一般的解题步骤:分析问题,弄清题意——从原问题中抽象出模型——根据模型设计状态,要求状态满足最优子结构和无后效性——直接设计状态有难度的话则需要考虑转化模型——根据设计的状态考虑转移——如果过不了题目要求的数据范围,则需要考虑优化由于动态规划涉及的内容太多,只言片语难以讲清,所以附件中放了很多篇关于动态规划的文章,大部分系原创,并附上了一些经典的论文,主要讲了DP的优化,一些特殊的状态设计技巧Dp和递推没有本质区别,都是用一些状态来描述问题,并记录下一些信息,根据已知信息推出未知信息,直到得到问题的解关于DP的优化有两篇神级论文,放在附件里面了,写的非常好。

二、图论及网络流最小生成树:克鲁斯卡尔算法和普利姆算法,——重要性质1:最小生成树上任意两点的路径的最大边最小——重要性质2:最小生成树的多解(方案个数)只与相同权值的的边有关(省队集训题生成树计数)最短路:spfa算法、堆+迪杰斯特拉算法Spfa算法是基于松弛技术的,随机图效果极佳,最坏(网格图或存在负权环)O(nm),适用于任意图,能够判断负权环——判负权环的方法:记录每个点当前从原点到它的最短路上边的条数,如果某次更新后这个条数>n-1则存在负权环堆+迪杰斯特拉则是用了贪心的思想,不断扩大确定dist的集合,同时更新dist,如果边权有负值就不能做,复杂度是O((n+m)logn)的拓扑排序:可以将有向图转化为一个线性的序列,满足一个点所有的前驱结点都出现在这个点在序列中的位置之前。

可以判断这个有向图是否有环——一个简单而实用的扩展:给树做类top排序,可以有类似的功能,即每次去掉叶子结点,将树转化为一个具有拓扑关系的序列——再扩展:树同构判断,可用类top确定树根是谁,再最小表示法+hash即可强连通分量、缩点:tarjan算法核心是每个点记一个时间戳ti[i], 另外low[i]表示i点能延伸出的搜索树中节点的ti[i]的最小值,还要维护个栈记当前路径上的点,low[i]初始化为ti[i],如果搜完i了,ti[i]=low[i]则当前栈顶到i的所有点会在一个强连同分量内。

最新NOIP初赛复习14基本算法思想总结

最新NOIP初赛复习14基本算法思想总结

最新NOIP初赛复习14基本算法思想总结NOIP初赛复习14基本算法思想一个程序往往要包含两个方面的描述:一是对数据组织的描述,就是数据的类型和数据的组织形式(例如数组),称作数据结构;一是对程序操作流程的描述,就是程序的操作步骤,也就是所谓算法。

正如著名的计算机科学家沃思(Nikiklaus Wirth)提出的公式:数据结构+算法=程序。

算法,广义地讲就是解决问题的方法和过程。

可以使用自然语言、伪代码、流程图等多种不同的方法来描述。

如果把一个程序比喻成一个具有生命的人,那么数据结构就是这个人的躯体,而算法则是这个人的灵魂。

枚举枚举法,又称穷举法,或称为暴力破解法,是一种针对于密码的破译方法,即将密码进行逐个推算直到找出真正的密码为止。

基本思想:在可能的解空间中穷举出每一种可能的解,并对每一个可能解进行判断,从中得到问题的答案。

虽然枚举法本质上属于搜索策略,但是它与后面讲的回溯法或宽度优先搜索有所不同。

总的来说,枚举就是通过列举所有的可能性进行一一判断检查。

适用条件:1、可预先确定每个状态的元素个数n。

2、可预先确定每个状态元素a1,a2,…,an的值域。

注意事项:使用枚举思想解决实际问题,最关键的步骤是划定问题的解空间,并在该解空间中一一枚举每一个可能的解。

这里有两点需要注意。

一是解空间的划定必须保证覆盖问题的全部解。

如果解空间集合用H表示,问题的解集用h表示,那么只有当时,才能使用枚举法求解。

二是解空间集合及问题的解集一定是离散的集合,也就是说集合中的元素是可列的、有限的。

常见类型:枚举排列、枚举子集。

常见方法:递归地枚举,这种方法往往更为直观;递推(循环)地枚举,这种方法往往写起来更为简洁。

主要优点:由于枚举算法一般是现实问题的“直译”,且是建立在考察大量状态、甚至是穷举所有状态的基础之上的,因此比较直观,易于理解,其算法的正确性也比较容易证明。

主要缺点:枚举算法的效率取决于枚举状态的数量以及单个状态枚举的代价,因此效率比较低。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

算法总结一、动态规划和递推dp一般的解题步骤:分析问题,弄清题意——从原问题中抽象出模型——根据模型设计状态,要求状态满足最优子结构和无后效性——直接设计状态有难度的话则需要考虑转化模型——根据设计的状态考虑转移——如果过不了题目要求的数据范围,则需要考虑优化由于动态规划涉及的内容太多,只言片语难以讲清,所以附件中放了很多篇关于动态规划的文章,大部分系原创,并附上了一些经典的论文,主要讲了DP的优化,一些特殊的状态设计技巧Dp和递推没有本质区别,都是用一些状态来描述问题,并记录下一些信息,根据已知信息推出未知信息,直到得到问题的解关于DP的优化有两篇神级论文,放在附件里面了,写的非常好。

二、图论及网络流最小生成树:克鲁斯卡尔算法和普利姆算法,——重要性质1:最小生成树上任意两点的路径的最大边最小——重要性质2:最小生成树的多解(方案个数)只与相同权值的的边有关(省队集训题生成树计数)最短路:spfa算法、堆+迪杰斯特拉算法Spfa算法是基于松弛技术的,随机图效果极佳,最坏(网格图或存在负权环)O(nm),适用于任意图,能够判断负权环——判负权环的方法:记录每个点当前从原点到它的最短路上边的条数,如果某次更新后这个条数>n-1则存在负权环堆+迪杰斯特拉则是用了贪心的思想,不断扩大确定dist的集合,同时更新dist,如果边权有负值就不能做,复杂度是O((n+m)logn)的拓扑排序:可以将有向图转化为一个线性的序列,满足一个点所有的前驱结点都出现在这个点在序列中的位置之前。

可以判断这个有向图是否有环——一个简单而实用的扩展:给树做类top排序,可以有类似的功能,即每次去掉叶子结点,将树转化为一个具有拓扑关系的序列——再扩展:树同构判断,可用类top确定树根是谁,再最小表示法+hash即可强连通分量、缩点:tarjan算法核心是每个点记一个时间戳ti[i], 另外low[i]表示i点能延伸出的搜索树中节点的ti[i]的最小值,还要维护个栈记当前路径上的点,low[i]初始化为ti[i],如果搜完i了,ti[i]=low[i]则当前栈顶到i的所有点会在一个强连同分量内。

var j,k:longint;begininc(time);ti[i]:=time;v[i]:=true;low[i]:=time;inc(ed);q[ed]:=i;j:=h[i];while j<>0 do begink:=point[j];if ti[k]=0 then begindfs(k);if low[k]<low[i] then low[i]:=low[k];endelseif v[k] then if ti[k]<low[i] then low[i]:=ti[k];j:=next[j];end;if ti[i]=low[i] then begininc(num);k:=0;repeatj:=q[ed];f[j]:=num;v[j]:=false;k:=k+a[j];if b[j] then bar[num]:=true;dec(ed);until q[ed+1]=i;vl[num]:=k;end;end;欧拉路:含义:不重复地经过每条边的一条路径,如果起点和终点相同则叫“欧拉回路”,起点和终点不同叫“欧拉路径”存在欧拉路径的条件:至多两个点的度为基数(回路则要求全都为偶数)实现:(非常简单)上面的代码中正边和反边的编号是相邻的,关注inc(ans[0])的位置,是在递归调用的后面哈密尔顿回路含义:经过所有点的一个回路这是个NPC问题,只有近似算法(暴搜就不提了)比较好用的是模拟退火,以环上相邻两点有边相连的个数作为估价值,随机化调整二分图匹配:最大匹配:匈牙利算法,理论O(nm),实际复杂度好很多最佳匹配:KM算法,理论O(n^2m),实际复杂度同匈牙利一样相当不错——重要性质:最小可行定标和= 最优匹配KM算法中构造了一个非常不错的不等式lx[i] + ly[j] >= w[i,j],有的题目可以利用这个不等式套KM求出最小可行定标和,如20101112 ti糟糕的传染网络流非常神奇的一个东西,数学味有余而图论味不足,通常用来解决限制条件太强,以至于无论如何都表示不了状态的题,很多经典例题见《网络流24题》通常使用的最大流算法是dinic,代码要背熟,一般能10分钟之内敲出来最大流最小割定理经典模型:最小割模型,最大权闭合图,平面图网络流转最小割——参考神文胡伯涛论文费用流相当于网络流的一个强化,能多处理一维信息。

具体来讲就是给边多加一个“费用”,每次增广的费用就是这条增广路的费用之和*流量。

费用流有最小费用最大流和最大费用最大流,用spfa每次找条最短(长)路增广即可最小费用最大流还可以用zkw算法加速,差不多比裸spfa+增广快10倍的样子(在二分图网络流上尤为明显),我和盾盾研究了一种更nb的费用流,我命名为“距离标号连续增广路费用流算法”,能够秒杀几千个点的稠密随机图,二分图就更不在话下了,速度几乎达到了dinic的三分之一的样子,而且实现非常简单!经典例题参考《网络流24题》三、贪心贪心的关键是找结论,同时给出证明,然后就可以利用这个结论来做题了当然,考场上对你猜出的结论给出证明通常是很难的,所以用贪心法解题需要丰富的经验,正确的“题感”,胆大心细才能搞出来由于经常要取最优值,所以常常与堆、平衡树等数据结构结合起来贪心+其他算法:由于贪心往往能大幅化简状态,利用问题的某些“单调性”,加上贪心的思想,往往能是问题大幅简化,从而结合其他算法解决问题经典例题:田忌赛马,利用贪心来确定状态四、分治分而治之的思想在信息学竞赛中是非常重要的,下面主要介绍一下分治的经典应用二分查找思想很简单,功能很强大,边界要注意,负数要特判(NOI2010 PIANO)在非负数范围内的二分一般写法如果是l := mid - 1或+ 1则mid := (l + r) div 2而如果是r := mid - 1 或+1则mid := (l + r + 1) div 2快速幂a^b = (a^(b div 2))^2 + ord(odd(b))*a取模也适用——扩展:求(1 + a + a^2 + a^3 + … + a^n) mod p的值O(logn)算法:分治1 + a + a^2 + a^3 + … + a^n= (1 + a + a^2 + a^3 + … + a^(n div 2))*a^(n div 2) + ord(odd(n))*a^n两个快速幂可以合到一起写快速排序,归并排序任何一本算法书上都会讲的,这里就略过了,值得一提的是快排记得加上随机化k := a[random(r - l + 1) + l]二分答案(0-1分数规划)当答案满足在解集空间中连续分布时可以使用二分答案,将最优性问题转化为判定性问题,通常标志:最大值最小等差分约束系统中有时也需要二分答案以解决最优性问题,顺便能多得到一个信息二分答案还有一个优势,那就是已经知道了答案,那就可能可以将一些直接做必须在线的操作转化为离线操作(也就是说,我可以排序然后判定),诸如要求你判定“第一句出现矛盾的话”之类的题目(poj 3657)0-1分数规划也是经典的利用二分答案来做的一类问题通常是要求你最小化f(x)/g(x)令ans = f(x)/g(x)则f(x) - g(x)*ans = 0重构权,将f(i) - g(i)*ans作为新权值,用相应算法求出一个“最小值”,判断是否>=0,接着二分即可详细说明及数学证明见集训队07胡伯涛论文树的分治一般用来解决树上的路径或统计类问题,每次只考虑跟树根有关的信息,然后递归分治处理树的分治通常有基于点或基于边的分治,基于点的难合,基于边的复杂度太高这里只介绍基于点的分治步骤:处理跟当前树根有关的信息重新计算子树大小在子树中选择重心为根,递归到相应子树处理因为每次选了重心,所以递归总共logn层,每层O(n)的复杂度,总复杂度就是O(nlogn) 更详细严谨的介绍见漆子超论文二分搜索直接搜的复杂度是指数级的的话,一般是40左右的数据量,hash一半,搜一半,搜后面的时候利用之前的hash信息合并出原问题的解而直接搜的复杂度达到阶乘级的话n一般就不超过20了,做法一般差不多经典例题:POI02szy,NOI2001方程的解数五、搜索作为信息学竞赛中的所谓“万能算法”,搜索可以说是计算机学科所具有的最大特点了,自然地,搜索算法的应用自然也是非常之广泛,除了专门的搜索题,搜索一般可以用来部分预处理,打表找规律,当然还有骗分搜索的一般步骤:确定状态——选择搜索方式(dfs、bfs)——确定产生式规则——开始搜索搜索的常见优化方式:改变状态表示这个需要根据题目而定,确定一个漂亮的状态表示,可能就有希望转向记忆化了,即使不行,搞出一个漂亮的状态表示是解决一道麻烦题的最重要的一步,再者,调试起来也会容易许多。

优化搜索顺序这个优化在多数搜索中能起到摧枯拉朽的提速效果,通常我们选择枝叶较少的儿子先扩展,例如大名鼎鼎的dancing Links,除了利用双向十字链表去除冗余状态,每次选择可扩展数最少的儿子扩展同样给它的神速创造了条件。

(poj的一道数独题,我在选择拿出去扩展的点的那个循环中<和<=的区别就是200ms和2000ms的区别)可行性剪枝以及最优性剪枝这是非常常用的剪枝思路之一,因题目而异,在迭代加深搜索中尤为重要一般思路:考虑每次解最多变优多少,从当前的层数来看还有多少改进空间,如果已经不可能成为解或更新答案则可以剪枝了——A*及IDA*算法:本质就是给搜索加上一个满足相容性的估价函数,然后用估价函数剪枝,理论上很牛B,实际上不常用,因为考场上很难想出满足那么多条件的估价函数,但记得一些常见模型的估价函数还是有价值的。

例如15数码的估价函数就可以选择除了0之外每个元素到自己该到的位置的曼哈顿距离之和,因为每次最多使一个数距离减少1,所以这个估价函数是相容的,再例如求k短路的A*算法就是用个堆维护min{ f(s) + g(s) }估价函数就是从汇点反搜的“反向最短路”的长度。

部分搜索+其他算法部分搜索+二分图匹配:楼天成《匹配算法在搜索问题中的巧用》经典例题:mt problem 2 milk(很郁闷的说,只用该算法仍不能ac之)六、数论和组合数学同余方程(组)#define (a mod b)->((a mod b + b) mod b)–>解决负数的问题解线性同余方程的方法:扩展欧几里德核心操作:求ax + by = gcd(a, b) = d先递归求a’y + b’(x mod y) = da’y + b’(x - x div y*y) = da’y + b’x – b’*(x div y)*y = db’x + (a’– b’*(x div y))*y = d有a = b’ b = a’ - b’*(x div y)边界:y = 0时,a = 1, b = 0解模方程ax mod b = c等价于解出ax + by = c无解的条件c mod gcd(a,b) <> 0求解ax +by = c令d = gcd(a, b), c’ = c div d求解原方程等价于求解ax + by = d, 求完后将答案乘上c’即可求ax mod b = c的最小正解的方法先求出一组ax + by = c的可行解x,y(实际上我们只要x)由a(x + k*b) mod b = c所以我们可以通过给x加上若干倍b使得a恰好大于0实际操作时,只要取x’ = x mod b就可以了,如果x’< 0 则x’ := x’ + b解同余方程组的方法:每次合并两个模方程,合到最后就能够解出来了核心操作:合并x mod a1 = b1x mod a2 = b2令x = a1*y + b1则(a1*y + b1) mod a2 = b2a1*y mod a2 = b2 - b1可以用扩展欧几里得求出y,从而求出最小正x同时满足两个方程合并之后变成x’ mod lcm(a1, a2) = x mod lcm(a1, a2)以此合并求解即可将带系数的方程化为不带系数的方法:ax mod b = c ⇔ax + by = c ⇔利用扩展欧几里得可解得x, y那么x的通解可以表示为x + k*(b div gcd(a, b))因此,原方程等价于x’ mod (b div gcd(a, b)) = x, x’是新的未知数,x是上面用扩展欧几里得解出来的东西,成功地等价地把系数消掉了素数和整除性问题判断素数的方法:O(sqrt(n)):从2枚举到sqrt(n)逐一判断即可均摊O(ln(n))的方法:筛选法利用费马小定理可以O(k*logn)地检验质数,但有一定概率出错(k是检验次数)组合计数类问题基本:排列和组合:C(N,M) = N!/(M!(N-M)!) P(N,M) = N!M!容斥原理:在计数时,必须注意无一重复,无一遗漏。

相关文档
最新文档