数论(Primer)

几个重要需要记住的内容:

1.欧几里得定理(辗转相除法)

int gcd(int a, int b){
    return b==0?a:gcd(b, a%b);
}

2.扩展欧几里得(求ax+by = gcd(a,b)的特解)

void e_gcd(LL a, LL b, LL &d, LL &x, LL &y){
    if(b==0){
        x = 1; y = 0; d = a;
    }
    else{
        e_gcd(b, a%b, d, y, x);
        y-= x*(a/b);
    }
}

3.中国剩余定理

同余方程组

x ≡ a1(mod m1)

x ≡ a2(mod m2)

... ...

x ≡ ak(mod mk)

方程组所有的解的集合就是:

x1 = N1*a1 + N2*a2 + ... + Nk*ak

其中 Ni mod mi = 1,Ni = ai * ti , 可用欧几里得扩展定理求 ti. 其中M = m1*m2*m3····*mn;

    #include <iostream>
    using namespace std;
    //参数可为负数的扩展欧几里德定理
    void exOJLD(int a, int b, int &x, int &y){
        //根据欧几里德定理
        if(b == 0){//任意数与0的最大公约数为其本身。
            x = 1;
            y = 0;
        }else{
            int x1, y1;
            exOJLD(b, a%b, x1, y1);
            if(a*b < 0){//异号取反
                x = - y1;
                y = a/b*y1 - x1;
            }else{//同号
                x = y1;
                y = x1 - a/b* y1;
            }
        }
    }
    //剩余定理
    int calSYDL(int a[], int m[], int k){
        int N[k];//这个可以删除
        int mm = 1;//最小公倍数
        int result = 0;
        for(int i = 0; i < k; i++){
            mm *= m[i];
        }
        for(int j = 0; j < k; j++){
            int L, J;
            exOJLD(mm/m[j], -m[j], L, J);
            N[j] = m[j] * J + 1;//1
            N[j] = mm/m[j] * L;//2 【注】1和2这两个值应该是相等的。
            result += N[j]*a[j];
        }
        return (result % mm + mm) % mm;//落在(0, mm)之间,这么写是为了防止result初始为负数,本例中不可能为负可以直接 写成:return result%mm;即可。
    }  

    int main(){
        int a[3] = {2, 3, 2};
        int m[3] = {3, 5, 7};
        cout<<"结果:"<<calSYDL(a, m, 3)<<endl;
    }  

4.欧拉函数(求一个数前面的所有与这个数互质的数的个数)

Euler函数表达通式:euler(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…(1-1/pn),其中p1,p2……pn为x的所有素因数,x是不为0的整数。euler(1)=1(唯一和1互质的数就是1本身)。

    //直接求解欧拉函数
    int euler(int n){ //返回euler(n)
         int res=n,a=n;
         for(int i=2;i*i<=a;i++){
             if(a%i==0){
                 res=res/i*(i-1);//先进行除法是为了防止中间数据的溢出
                 while(a%i==0) a/=i;
             }
         }
         if(a>1) res=res/a*(a-1);
         return res;
    }  

    //筛选法打欧拉函数表
    #define Max 1000001
    int euler[Max];
    void Init(){
         euler[1]=1;
         for(int i=2;i<Max;i++)
           euler[i]=i;
         for(int i=2;i<Max;i++)
            if(euler[i]==i)
               for(int j=i;j<Max;j+=i)
                  euler[j]=euler[j]/i*(i-1);//先进行除法是为了防止中间数据的溢出
    }  
时间: 2024-12-26 14:45:05

数论(Primer)的相关文章

HDU 4002 Find the maximum(数论-欧拉函数)

Find the maximum Problem Description Euler's Totient function, φ (n) [sometimes called the phi function], is used to determine the number of numbers less than n which are relatively prime to n . For example, as 1, 2, 4, 5, 7, and 8, are all less than

NKOJ1236 a^b (数论定理的应用)

          a^b 对于任意两个正整数a,b(0<=a,b<10000)计算a b各位数字的和的各位数字的和的各位数字的和的各位数字的和. Input 输入有多组数据,每组只有一行,包含两个正整数a,b.最后一组a=0,b=0表示输入结束,不需要处理. Output 对于每组输入数据,输出ab各位数字的和的各位数字的和的各位数字的和的各位数字的和. Sample Input 2 3 5 7 0 0 Sample Output 8 5 思路: 数论定理:任何数除以9的余数等于各位数的和除

C++ Primer快速学习 第一章 入门

很多人说C++Primer不适合于入门,本系列入门文章向大家证明了:这是一个谎言. 第一章 入门 本章介绍 C++ 的大部分基本要素:内置类型.库类型.类类型.变量.表 达式.语句和函数. 1.1. 编写简单的 C++ 程序 每个 C++ 程序都包含一个或多个 函数 ,而且必须有一个命名为 main.函数 由执行函数功能的语句序列组成.操作系统通过调用 main 函数来执行程序, main 函数则执行组成自己的语句并返回一个值给操作系统. 下面是一个简单的 main 函数,它不执行任何功能,只是

CodeForces 396A 数论 组合数学

题目:http://codeforces.com/contest/396/problem/A 好久没做数论的东西了,一个获取素数的预处理跟素因子分解写错了,哭瞎了,呵呵, 首先ai最大值为10^9,n为500,最坏的情况 m最大值为500个10^9相乘,肯定不能获取m了,首选每一个ai肯定是m的一个因子,然后能分解就把ai给分解素因子,这样全部的ai都分解了  就能得到m的 所有素因子 以及 所有素因子的个数,题目求的 是n个因子的 不同序列的个数,所以每次 只能选出n个因子,这n个因子由素因子

C++ Primer Plus的若干收获--(八)

接下我会比较系统的介绍OOP的核心--类这个概念.可能会写的比较繁琐,比较多,但是自己理解总是好的.还记得上学期刚开始的时候老师讲的数据结构,一上来就来个LIst的一个大类,结果全班就傻了,完全不知所云(ps:博主是数学系,只学过C),然后自己就坐在图书馆借了两大本C++书开始啃了起来,大概啃了两个月才把C++学了个大概,尤其是读到类这块都是三四百行的常常的代码,看的那叫一个痛苦啊.不过自此之后就真正喜欢上这门语言了,再到之后能用C++写上个一两千行的代码,才发现之前的努力还是有收获的.好了,废

HDU 4861 Couple doubi(数论)

HDU 4861 Couple doubi 题目链接 题意:给定k,p,有k个球,每个球的值为1^i+2^i+...+(p-1)^i (mod p) (1 <= i <= k),现在两人轮流取球,最后球的值总和大的人赢,问先手是否能赢 思路:先手不可能输,非赢即平,那么只要考虑每种球的值, 利用费马小定理或欧拉定理,很容易得到该函数的循环节为p - 1, 那么i如果为p - 1的倍数,即为循环节的位置,那么每个值都为1,总和为p - 1 如果i不在循环节的位置,任取一个原根g,根据原根的性质,

UVA 10548 - Find the Right Changes(数论)

UVA 10548 - Find the Right Changes 题目链接 题意:给定a,b,c,表示货物的价值,求由A货物和B货物组成C货物有几种方法,判断有无解和是否有无限多种 思路:扩展欧几里得求通解,去计算上限和下限就能判断 代码: #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const long l

C++ Primer笔记8_动态内存_智能指针

1.动态内存 C++中,动态内存管理是通过一对运算符完成的:new和delete.C语言中通过malloc与free函数来实现先动态内存的分配与释放.C++中new与delete的实现其实会调用malloc与free. new分配: 分配变量空间: int *a = new int; // 不初始化 int *b = new int(10); //初始化为10 string *str = new string(10, ); 分配数组空间: int *arr = new int[10];//分配的

C++ Primer 学习笔记_98_特殊工具与技术 --优化内存分配

特殊工具与技术 --优化内存分配 引言: C++的内存分配是一种类型化操作:new为特定类型分配内存,并在新分配的内存中构造该类型的一个对象.new表达式自动运行合适的构造函数来初始化每个动态分配的类类型对象. new基于每个对象分配内存的事实可能会对某些类强加不可接受的运行时开销,这样的类可能需要使用用户级的类类型对象分配能够更快一些.这样的类使用的通用策略是,预先分配用于创建新对象的内存,需要时在预先分配的内存中构造每个新对象. 另外一些类希望按最小尺寸为自己的数据成员分配需要的内存.例如,