CSP考纲及高精度计算

江枫思渺然 提交于 2019-11-30 15:00:54

转载请注明出处,部分内容引自

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;
}
 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!