CSP考纲及高精度计算
转载请注明出处,部分内容引自
SBSOI大佬
首先来一张图,很直观(截止到2012年数据)
下面是收集的一些,我改了一下
加粗表示特别重要,必须掌握
其他表示最好掌握,可能性不是很大,但是某些可以提高程序效率
高精度
a.加法
b.减法
c.乘法(应该只会有高精乘单精)
d.高精度除单精 (后面c,d考的可能性较小,应该只考a,b)
排序算法
a.选择排序
b.插入排序
c.hash排序
d.归并排序(单纯的排序可能用不到,有快排就行了,但是归并排序的思想很重要)
e.堆排序
f.快排
字符串匹配算法
a.蛮力法
b.KMP
数论
a.欧几里德算法(用辗转相除法求最大公约数)
b.扩展欧几里德算法 ax+by=c 的正整数
c.素数 O(sqrt(n))
d.筛法求素数
e.快速乘方(位运算+同余+高精)
树论
a.二叉搜索树
b.优先队列(C++中priority_queue,相当于手动维护的小(大)根堆的数据结构优化)
c.线段树 (RMQ问题建议使用st算法)
d.平衡树一种(建议学习SBT)
图论
a.拓扑排序
b.割顶,割边(桥) {O(n)}
c.强连通分支 O(n)
d.有向无回路图的最长路径
e.欧拉回路
f.最小生成树
① Prime O(N2)
② Kruskal O(M2)
g.次小生成树 {简单的删除最大边是不对的}
h.最短路径
① Dijkstra
② Bellman-ford
③ spfa
④ flyod
单源点最短路径算法推荐使用spfa(即使你习惯dijkstra),Dijkstra不能有负边不能有回路,所以用spfa更保险
计算几何
a.判断两条线段是否相交
b.凸包算法 O(n)
其他算法
a.并查集
b.RMQ
......
高精度算法
1、高精度加法(简单版,以noi1.6:10大整数加法题为例)
//noi1.6:10大整数加法 //题解:高精度入门题:结构体+字符转换+进位 #include<cstdio> #include<cstring> struct nod{int n,a[210];nod(){memset(a,0,sizeof(a));}}a,b; char s[210]; int main() { int ns;//读入a============ scanf("%s",s+1);//下标从1开始 ns=strlen(s+1); a.n=ns; for(int i=1;i<=ns;i++)//字符逆序转换为数字 {//为了数位 对齐,翻转数字 a.a[ns-i+1]=s[i]-'0'; }//======================== //读入b==================== scanf("%s",s+1);//下标从1开始 ns=strlen(s+1); b.n=ns; for(int i=1;i<=ns;i++)//字符逆序转换为数字 {//为了数位 对齐,翻转数字 b.a[ns-i+1]=s[i]-'0'; }//========================= //模拟加法运算 a.n=a.n>b.n?a.n:b.n;//确定数位 for(int i=1;i<=a.n;i++)//暴力加 { a.a[i]+=b.a[i]; } for(int i=1;i<=a.n;i++)//处理进位 { if(a.a[i]>9) { a.a[i+1]+=a.a[i]/10;//向右进位 a.a[i]%=10;//保留个位数 if(i==a.n) a.n++;//最高位溢出 } } //消除前导0 while(a.a[a.n]==0&&a.n>1) a.n--;//最高位必须非0 //反向输出 for(int i=a.n;i>=1;i--) { printf("%d ",a.a[i]); } return 0; }
2、高精度减法(简单版,以noi1.6:11大整数减法题为例)
//noi1.6:11大整数减法 //题解:高精度入门题:结构体+字符转换+借位 #include<cstdio> #include<cstring> struct nod{int n,a[210];nod(){memset(a,0,sizeof(a));}}a,b; char s[210]; int main() { int ns;//读入a============ scanf("%s",s+1);//下标从1开始 ns=strlen(s+1); a.n=ns; for(int i=1;i<=ns;i++)//字符逆序转换为数字 {//为了数位 对齐,翻转数字 a.a[ns-i+1]=s[i]-'0'; }//======================== //读入b==================== scanf("%s",s+1);//下标从1开始 ns=strlen(s+1); b.n=ns; for(int i=1;i<=ns;i++)//字符逆序转换为数字 {//为了数位 对齐,翻转数字 b.a[ns-i+1]=s[i]-'0'; }//========================= //模拟减法运算 for(int i=1;i<=a.n;i++) a.a[i]-=b.a[i];//暴力减 for(int i=1;i<=a.n;i++)//处理借位 { if(a.a[i]<0) { a.a[i+1]-=1;//向右借 1 a.a[i]+=10;//补充数值 } } //消除前导0//本题保证a>b,如果不知道大小关系呢? while(a.a[a.n]==0&&a.n>1) a.n--;//最高位必须非0 //反向输出 for(int i=a.n;i>=1;i--) printf("%d",a.a[i]); return 0; }
3、高精度乘法(有两种:高精度*低精度,高精度*高精度)
(以下代码只展示高精度*低精度,以noi1.6:12:计算2的N次方 题为例)
//noi1.6:12计算2的N次方 //题解:高精度*低精度 +非结构体 +函数 #include<cstdio> int a[1010],na;//估算数组,2的100次不知道是多少位? //10的100次是1000位,可以了吗? void cf(int x) { for(int i=1;i<=na;i++)//每位都乘 { a[i]*=x; } for(int i=1;i<=na;i++)//处理进位 { if(a[i]>9) { a[i+1]+=a[i]/10; a[i]%=10; if(i==na) na++;//最高位溢出 } } } int main() { int n; scanf("%d",&n); a[1]=1;na=1; for(int i=1;i<=n;i++) { cf(2); } for(int i=na;i>=1;i--) printf("%d",a[i]);//反向输出 //现在你可以知道2的100次方是多少位了吗? return 0; }
4、高精度除法(有两种:高精度/低精度,高精度/高精度)
(以下代码只展示高精度/低精度,以noi1.6:13:大整数的因子 题为例)
//noi1.6:13大整数的因子 //题解:高精度除以低精度:模拟思想 #include<cstdio> #include<cstring> char s[210]; int a[210],na,ls=0; void chu(int x) { int k=0;//余数 for(int i=na;i>=1;i--)//模拟竖式除法 { k=k*10+a[i]; k=k%x; } if(k==0) { ls=1; //打标签 printf("%d ",x); } } int main() { int ns; scanf("%s",s+1);//下标从1开始 ns=strlen(s+1); na=ns; for(int i=1;i<=ns;i++)//字符逆序转换为数字 { a[ns-i+1]=s[i]-'0'; } for(int i=2;i<=9;i++) { chu(i);//函数处理 } if(ls==0) printf("none"); return 0; }