[算法] 数学问题

  1. <cmath>中常用函数
    pow(base, exponent)
    sqrt(x)
    fmax、fmin、fabs
    ceil、floor、round(四舍五入)
    上述这些返回值和参数默认都是浮点数 注意强制类型转换 注意double强制转int 向下舍入
    e.x. %的除数和被除数都必须为整型变量且除数不能为0否则runtime error
    abs的返回值虽然是整型,但它同时为整型和浮点型重载,可替代fabs
    fmin、fmax是<cmath>中求最值的方法,不过我们通常使用algorithm头文件中的min 、max,后者还可以自定义比较函数

  2. 模运算

  • 负数取模
    e.x. 日期与当前日期的天数差值可能为负
    (days % 7 + 7) % 7
    加上求模的除数仍要再取一次模,保证原来模为0的情况仍为0

  • 大数求模
    (a*b) % c = (a % c * b % c) % c
    (a+b) % c = (a % c + b % c ) % c

  1. GCD & LCM
    最大公约数 Greatest Common Divisor
    欧几里得算法 辗转相除
while( b!= 0) {
int t = a % b;
a = b;
b = t;
}
return a;
// 一行
int gcd(int a, int b)
{
    return b ? gcd(b, a % b) : a;
}

最小公倍数 Least Common Multiple
a * b / gcd(a,b)

  1. 素数
  • 试除法素数判定
    因子必定是成对出现的
bool is_prime(int x)
{
    if (x < 2) return false;
    for (int i = 2; i <= x / i; i ++ )
        if (x % i == 0)
            return false;
    return true;
}
  • 素数筛法
    1到n中期望意义上有n/ \ln n个素数。
    Sieve of Eratosthenes 排除法
    O(n*log(log(n)))
int primes[N], cnt;     // primes[]存储所有素数
bool st[N];         // st[x]存储x是否被筛掉
void get_primes(int n)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (st[i]) continue;
        primes[cnt ++ ] = i;
        for (int j = i; j <= n; j += i)
            st[j] = true;
    }
}

Sieve of Euler 欧拉筛法
O(n) 每个数只被它最小的质因子筛掉

int primes[N], cnt;     // primes[]存储所有素数
bool st[N];         // st[x]存储x是否被筛掉

void get_primes(int n)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i]) primes[cnt ++ ] = i;
        for (int j = 0; primes[j] <= n / i; j ++ )
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) break;
        }
    }
}
  1. 分解质因数
    试除法分解质因数
void divide(int x)
{
    for (int i = 2; i <= x / i; i ++ )
        if (x % i == 0)
        {
            int s = 0;
            while (x % i == 0) x /= i, s ++ ;
            cout << i << ' ' << s << endl;
        }
    if (x > 1) cout << x << ' ' << 1 << endl;
    cout << endl;
}

最后要多加一步x>1的判断,因为最多只有一个大于\sqrt n的质因子

试除法求所有约数
大小为a的数的期望的约数个数为\ln a

vector<int> get_divisors(int x)
{
    vector<int> res;
    for (int i = 1; i <= x / i; i ++ )
        if (x % i == 0)
        {
            res.push_back(i);
            if (i != x / i) res.push_back(x / i);
        }
    sort(res.begin(), res.end());
    return res;
}

如果 N = p1^c1 * p2^c2 * ... *pk^ck
约数个数: (c1 + 1) * (c2 + 1) * ... * (ck + 1)
约数之和: (p1^0 + p1^1 + ... + p1^c1) * ... * (pk^0 + pk^1 + ... + pk^ck)
求解幂次求和
普通做法O(n)
分治O(lgn)

  1. 数位拆解
    do{
    } while(a != 0);
    可避免数本身为0时未分解到任何结果的情况
  2. 进制转换
  • 注意字符与数字比较时一定记得加单引号'0'
  • 注意向字符串转换和从字符串转换时的反序和反向遍历操作
  • 注意处理0和负数
    从字符串转换时判断s[0] == '-' ,向字符串转换时0和负数的构造
  1. 高精度
  • 高精度加法
vector<int> bigAdd(vector<int>& a, vector<int>& b) {
    vector<int> res;
    int alen = (int)a.size();
    int blen = (int)b.size();
    for (int i = 0, g = 0; ; i++) {
        if (g == 0 && i >= alen && i > blen) {
            break;
        }
        if (i < alen) {
            g += a[i];
        }
        if (i < blen) {
            g += b[i];
        }
        res.push_back(g % BASE);
        g /= BASE;
    }
    return res;
}
  • 高精度乘法
vector<int> bigMul(vector<int>& a, vector<int>& b) {
    int alen = (int)a.size();
    int blen = (int)b.size();
    int index;
    for (index = 0; index < a.size() && a[index] == 0; index++) {}
    if (index == a.size()) return { 0 };
    for (index = 0; index < b.size() && b[index] == 0; index++) {}
    if (index == b.size()) return { 0 };
    vector<int> res(alen + blen, 0);
    // i*j存放i+j
    for (int i = 0; i < alen; i++) {
        for (int j = 0; j < blen; j++) {
            res[i + j] += a[i] * b[j];
        }
    }
    int g = 0;
    for (int i = 0; i < (int)res.size(); i++) {
        int tmp = res[i] + g;
        res[i] = tmp % BASE;
        g = tmp / BASE;
    }
    while (res.back() == 0) {
        res.pop_back();
    }
    return res;
}
  • 高精度求模
  1. 快速幂
    基于倍增的思想
求 m^k mod p,时间复杂度 O(logk)。
int qmi(int m, int k, int p)
{
    int res = 1 % p, t = m;
    while (k)
    {
        if (k&1) res = res * t % p;
        t = t * t % p;
        k >>= 1;
    }
    return res;
}

矩阵快速幂

mat qPow (mat A, ll n) {
    int len = (int)A.size();
    mat res(len, vector<BigInt>(len));
    res[0][0] = res[1][1] = 1;
    res[0][1] = res[1][0] = 0;
    while (n) {
        if ( n & 1 ) {
            res = matrixMultiply(res, A);
        }
        A = matrixMultiply(A, A);
        n >>= 1;
    }
    return res;
}
  1. 求组合数
    Cnk mod p
  2. k <= 2000 递推法
// c[a][b] 表示从a个苹果中选b个的方案数
for (int i = 0; i < N; i ++ )
    for (int j = 0; j <= i; j ++ )
        if (!j) c[i][j] = 1;
        else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
  1. k <= 10^5 逆元法 预处理

乘法逆元

  • 定义
    若整数b,m互质,并且b|a,则存在一个整数x,使得a/b≡a∗x(mod m),则称x为b的模m乘法逆元,记为b^{−1} (mod \; m)
    逆元可以避免数论中除法产生非整数的情况
  • 乘法逆元的特点
    bb^{-1} ≡ 1 (mod \; m)
    乘法逆元的应用

    又根据 费马小定理
    b^{p-1} ≡ 1 (mod \; p)
    可得b存在乘法逆元的充要条件是b与模数m互质且当模数m为质数时,b^{m−2}即为b的乘法逆元;而如果m不是质数,则求逆元只能用扩展欧几里得定理
  • 应用
    求组合数


    组合数阶乘
  1. k <= 10^18 p是质数 Lucas定理


  2. 欧拉函数
    欧拉函数 \phi(n) = 1到n中与n互质的n个数
    欧拉定理
    如果n是素数,\phi(n) = p - 1
    如果n是合数,n = p_1^{a_1}p_2^{a_2}...p_r^{a_r},
    \phi(n) = n(1- 1/p_1)(1- 1/p_2)...(1- 1/p_r)

推广费马小定理
如果n是任一整数且a与n互素
a^{\phi(n)} ≡ 1 (mod \; m)

  1. 扩展欧几里得函数
    如果d|a且d|b,则d|(a+b), d|(qa + pb)

裴蜀定理
有任意正整数a, b,gcd(a,b)=d,那么对于任意的整数x,y,ax+by都一定是d的倍数,特别地,一定存在整数x,y,使ax+by=d成立。
推论
a,b互素的充要条件是存在整数x,y使ax+by=1

  1. 高斯消元
    O(n^3)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,099评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,473评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,229评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,570评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,427评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,335评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,737评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,392评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,693评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,730评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,512评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,349评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,750评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,017评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,290评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,706评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,904评论 2 335

推荐阅读更多精彩内容

  • 在C语言中,五种基本数据类型存储空间长度的排列顺序是: A)char B)char=int<=float C)ch...
    夏天再来阅读 3,286评论 0 2
  • 专业考题类型管理运行工作负责人一般作业考题内容选项A选项B选项C选项D选项E选项F正确答案 变电单选GYSZ本规程...
    小白兔去钓鱼阅读 8,957评论 0 13
  • 姓名:李浩然 学号:16030410020 转自:http://blog.csdn.net/Dreaming_My...
    洛花无阅读 2,579评论 0 1
  • 计算机二级C语言上机题库(南开版) 1.m个人的成绩存放在score数组中,请编写函数fun,它的功能是:将低于平...
    MrSunbeam阅读 6,282评论 1 42
  • 第二周作业:付费就是捡便宜 这周的问答环节有点意思,相对正文来说感觉触动更多。就针对获得的注意力用来干嘛这个也...
    夏目目阅读 280评论 0 0