ACM - 第10章 数论

10.1.1 除法表达式

gcd递归层数最多4.785lgN + 1.6723, N = max(a, b)

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

10.1.2 无平方因子数

主要讲的是素数的问题.

Eratosthenes 筛法

cmemset(vis, 0, sizeof(vis));
for(int i = 2; i <=n ;i++)
    for(int j = i*2; j <=n; j+= i) vis[j] = 1;

由此一来就可以筛选出素数,不过不是线性筛法,相信佳哥也一定知道...

循环的总次数小于n/2 + n/3 + ... n/n = o(nlogn)

欧拉1734年的结果: 1 + 1/2 + 1/3 + .. 1/n = ln(n+1) + y

允许在 $10^6$ 以内的所有素数.

  • 通过素数定理求素数的个数:

PI(x) ~ x/lnx

10.1.3 直线上的点

扩展欧几里德算法求解.

g = gcd(a,b), 方程解为(x0c/g, y0c/g)

cvoid gcd(int a, int b, int& d, int& x, int& y)
{
    if(!b) { d = a; x = 1; y = 0;}
    else { gcd(b, a%b, d, y, x); y -= x*(a/b); }
}

10.1.4 同余模算数

公式

(a+b) mod n = ((a mod n) + (b mod n)) mod n
(a-b) mod n = ((a mod n) - (b mod n) + n) mod n
ab mod n = (a mod n)(b mod n) mod n

乘法取余

cint mul_mod(int a, int b, int n)
{
    a %= n; b %=n;
    return (int)((long long) a * b % n);
}

大整数取MOD

cint big_int(char *n, int m)
{
    int len = strlen(n);
    int ans = 0;
    for(int i = 0; i < len; i++)
        ans = (int)(((long long)ans * 10 + (n[i]-'0')) % m);
    return ans;
}

幂取模

cint pow_mod(int a, int n, int m)
{
    int x = pow_mod(a, n/2, m);
    long long ans = (long long)x * x % m;
    if (n % 2 == 1)
        ans = ans * a % m;
    return (int) ans;
}

模线性方程

有一处没看明白,为何ax-b是n的正整数倍,而不是(a-b)x?

10.2.1 杨辉三角和二项式定理

给定n求(a+b)^n所有项的系数

c    memset(C, 0, sizeof(C));
    for(int i = 0; i <= n; i++)
    {
        C[i][0] = 1;
        for(int j = 1; j <= n; j++) C[i][j] = C[i-1][j-1] + C[i-1][j];
    }
  • 10-4

提供一种思路,就是大数字的乘除法可以借用素数和指数来表示.

10.2.2 数论中的计数问题

  • 10-5

分解质因数

  • 10-6 小于n且与n互素的数的个数

欧拉函数

cint euler_phi(int n)
{
    int m = (int) sqrt(n + 0.5);
    int ans = m;
    for(int i = 2; i <= m; i++) if(n % i == 0)
    {
        ans = ans / i*(i-1);
        while(n % i == 0) n /= i;
    }
    if(n > 1) ans = ans/n * (n-1);
    return ans;
}

// 筛法求范围内的欧拉函数 
void phi_table(int n, int *phi)
{
    for(int i = 2; i <= n; i++) phi[i] = 0;
    phi[1] = 2;
    for(int i = 2; i <= n; i++) if(!phi[i])
        for(int j = i; j <= i; j+= i)
        {
            if(!phi[j]) phi[j] = j;
            phi[j] = phi[j] / i * (i-1);
        }
}

编码解码

编码解码更多的利用树来构造.

10.2.4 离散概率初步

  • 生日的问题

边乘边除

cdouble birthday(int n, int m)
{
    double ans = 1.0;
    for(int i = 0; i < m ;i++) ans *= (n-1)/n;
    return 1-ans;
}

10.3.1 汉诺塔

利用数学归纳法来证明问题

10.3.2 Fibonacci数列

递推式,1,1,2,3,5,8...

10.3.3 Catalan 数

凸多边形的三角划分数量,车入栈出站方法均是卡特兰数.
计算方法

$f(n) = f(2)f(n-1) + f(3)f(n-2) + ... f(n-1)f(2)$

或者

$f(n+1) = (4n-6)/n * f(n)$

1,2,5,14,42,132,429,1430,4862,16796.

10.3.4 危险的组合

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值