ゆらのふなびと

競プロ, Python, C++

【競プロ整数ライブラリ】蟻本 2-6章 まとめ

蟻本2-6章を読んで素数・約数系のライブラリ的なものができたのでまとめておきます。説明は全部蟻本にあるぞい。

【なかみ】

  • gcd(a, b): aとbの最大公約数
  • lcm(a, b): aとbの最小公倍数
  • extgcd(a, b, &x, &y): ax + by = gcd(a,b) の解(x,y)を得る(拡張ユーグリッド互除法)
  • is_prime(n): 素数判定 O(\sqrt{n})
  • vector divisor(n): 約数のvectorを返す
  • map<int, int> prime_factor(n): 素因数分解(25*32 = {2:5, 3:2}みたいな感じで返ってくる)
  • sieve(n): エラトステネスのふるい(nまでの素数表を作る)
  • count_prime(a, b): [a, b)内の素数の個数を返す
  • mod_pow(x, n, mod): xn % modを高速演算
  • getFib(k): k番目までのフィボナッチ数を求める(2016/02/10 19:18 追加)

(2016/02/09 23:17 追記) ご指摘をいただいたのですが、lcmは a * b / gcd(a, b) ではなく a / gcd(a, b) * b と先に割った方がいいみたいです!(オーバーフローを防ぐため)そのように改訂させていただきました。

(2016/02/10 20:03 追記) getFibは 1, 2, 3, 5, 8, ... の順になっています。1, 1, 2, 3, 5,...としたい場合はif文2つを以下のように書き換えてください。(k=2の場合はループで計算されるので不要)

    if (k == 0 || k == 1) return 1;

(2016/02/12 18:35 追記) getFibは行列を用いると O(\log N)で実装可能です!(蟻本 p.180)

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <map>
#include <string>
#include <vector>
#include <cmath>
using namespace std;

#define REP(i,n) for(int i = 0; i < (int)(n); ++i)
#define pb push_back
#define ALL(a) (a).begin(),(a).end()

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

int lcm(int a, int b) {
    return a / gcd(a, b) * b ;
}

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

bool is_prime(int n) {
    for (int i = 2; i * i <= n; i++) {
        if (n % i == 0) return false;
    }
    return n != 1;
}

vector<int> divisor(int n) {
    vector<int> res;
    for (int i = 1; i * i <= n; i++) {
        if (n % i == 0) {
            res.pb(i);
            if (i != n / i) res.pb(n / i);
        }
    }
    return res;
}

map<int, int> prime_factor(int n) {
    map<int, int> res;
    for(int i = 2; i * i <= n; i++) {
        while(n % i == 0) {
            ++res[i];
            n /= i;
        }
    }
    if (n != 1) res[n] = 1;
    return res;
}

const int MAX_N = 10000000;
int prime[MAX_N];
bool memo[MAX_N + 1];

int sieve(int n) {
    int p = 0;
    REP(i ,n) memo[i] = true;
    memo[0] = memo[1] = false;
    for (int i = 2; i <= n; i++) {
        if (memo[i]) {
            prime[p++] = i;
            for (int j = 2 * i; j <= n; j += i) memo[j] = false;
        }
    }
    return p;
}

typedef long long ll;

const ll MAX_LEN = 1000000;
const ll MAX_SQRT_B = 1000000;
bool memo_all[MAX_LEN];         //i means i + a
bool memo_small[MAX_SQRT_B];

ll count_prime(ll a, ll b) {
    for (int i = 0; (ll)i * i < b; i++) memo_small[i] = true;
    for (int i = 0; i < b - a; i++)     memo_all[i] = true;

    for (int i = 2; (ll)i * i < b; i++) {
        if (memo_small[i]) {
            for (int j = 2; (ll)j * j < b; j += i) memo_small[j] = false;
            for (ll j = max(2LL, (a + i - 1) / i) * i; j < b; j += i) memo_all[j - a] = false;
        }
    }

    ll ret = 0;
    for (ll i = a; i < b; i++) {
        if (memo_all[i]) ret++;
    }
    return ret;
}

ll mod_pow(ll x, ll n, ll mod) {
    if (n == 0) return 1;
    ll res = mod_pow(x * x % mod, n / 2, mod);
    if (n & 1) res = res * x % mod;
    return res;
}

const int MAX_FIB_LEN = 100000;
ll fibdp[MAX_FIB_LEN];
ll getFib(int k) {
    if (k == 0) return 1;
    if (k == 1) return 2;
    if (fibdp[k] != 0) return fibdp[k];
    return fibdp[k] = getFib(k-1) + getFib(k-2);
}