数论模板1

来源:互联网 发布:日语翻译软件 知乎 编辑:程序博客网 时间:2024/05/20 16:08

参照Stanford Team Notebook

加入get_prime函数

修正chinese_reminder变量顺序错误


//无全局变量#include <cstdio>#include <cstring>#include <cstdlib>#include <iostream>#include <vector>#include <algorithm>using namespace std;typedef vector<int> VI;typedef pair<int, int> PII;//O(n)打1..n的素数表,附带因子分解功能, factor[i]给出i的最小素因子(factor[1] = 1)void get_prime(int n, VI & prime, VI & factor){    prime.clear();    factor.resize(n + 1);    for (int i = 1; i <= n; i++)        factor[i] = i;    for (int i = 2; i <= n; i++)    {        if (i == factor[i])            prime.push_back(i);        for (int j = 0; j < prime.size() && prime[j] * i <= n; j++)        {            factor[i * prime[j]] = prime[j];            if (i % prime[j] == 0)                break;        }    }}//a对b取正数模int mod(int a, int b){    return ((a % b) + b) % b;}//最大(正)公约数, 非递归int gcd(int a, int b){    int tmp;    while(b)    {        a %= b;        tmp = a;        a = b;        b = tmp;    }    if (a < 0)        a = -a;    return a;}//最小(正)公倍数(注意可能会超int范围)int lcm(int a, int b){    int ans = a / gcd(a, b) * b;    if (ans < 0)        ans = -ans;    return ans;}//非递归扩展欧几里得, 求解ax + by = gcd(a, b)int extended_euclid(int a, int b, int & x, int & y){    int xx = y = 0,        yy = x = 1;    while(b)    {        int q = a / b;        int t = b; b = a % b; a = t;        t = xx; xx = x - q * xx; x = t;        t = yy; yy = y - q * yy; y = t;    }    if (a < 0)    {        a = -a;        x = -x;        y = -y;    }    return a;}//求乘法逆元x(ax = 1 (mod n)), 无逆元则输出-1int mod_inverse(int a, int n){    int x, y;    int d = extended_euclid(a, n, x, y);    if (d != 1)        return -1;    else        return mod(x, n);}//求解模线性方程ax = b (mod n), 返回x的所有可能取值(无序)VI mod_linear_equation(int a, int b, int n){    int x, y;    VI ret;    int d = extended_euclid(a, n, x, y);    if (b % d == 0)    {        x = mod(x * (b / d), n);        for (int i = 0; i < d; i++)            ret.push_back(mod(x + i * (n / d), n));    }    return ret;}//求解线性丢番图方程ax + by = c, 成功返回0, 失败返回-1int linear_diophantine(int a, int b, int c, int & x, int & y){    int d = extended_euclid(a, b, x, y);    if (c % d != 0)        return -1;    else    {        x *= c / d;        y *= c / d;        return 0;    }}//中国剩余定理(x = a1 (mod x1),x = a2(mod x2), 不要求x1与x2互质//返回值意义为x = first (mod second),失败则返回的second为-1PII chinese_remainder(int a1, int x1, int a2, int x2){    int n1, n2;    if (linear_diophantine(x1, -x2, a2 - a1, n1, n2) == -1)        return make_pair(0, -1);    else        return make_pair(mod(a1 + n1 * x1, lcm(x1, x2)), lcm(x1, x2));}//中国剩余定理完全体,求解方程组x = ai (mod xi), i = 0...n - 1, 不要求模数互质//返回值意义为x = first (mod second),失败则返回的second为-1PII chinese_remainder(const VI & a, const VI & x, int n){    PII ret = make_pair(a[0], x[0]);    for (int i = 1; i < n; i++)    {        ret = chinese_remainder(ret.first, ret.second, a[i], x[i]);        if (ret.second == -1)            break;    }    return ret;}int main(){//    printf("%d\n", gcd(14, 30));//    printf("%d\n", lcm(14, 30));//    int x, y;//    printf("%d\n", extended_euclid(15, 34, x, y));//    printf("%d %d\n", x, y);//    printf("%d\n", mod_inverse(9, 19));//    VI ans = mod_linear_equation(14, 30, 100);//    for (int i = 0; i < ans.size(); i++)//        printf("%d\n", ans[i]);//    if (linear_diophantine(7, 2, 5, x, y) != -1)//        printf("solution: x = %d, y = %d\n", x, y);//    else//        printf("no solution\n");//    int aa[5] = {2, 3, 2, 3, 5},//        xx[5] = {3, 5, 7, 4, 6};//    VI avi(aa, aa + 5), xvi(xx, xx + 5);//    PII ans2;//    ans2 = chinese_remainder(avi, xvi, 3);//    cout << ans2.first << " " << ans2.second << endl;//    VI pri, fac;////    此处可以将pri和fac声明在main函数内,vector内的元素在堆上//    get_prime(100, pri, fac);//    for (int i = 0; i < pri.size(); i++)//        printf("%d%c", pri[i], (i == pri.size() - 1) ? '\n' : ' ');//    for (int i = 1; i < fac.size(); i++)//        printf("%d : %d\n", i, fac[i]);    return 0;}


原创粉丝点击