算法模板

算法模板

数论

//最大公约数
int gcd(int a, int b) {
  if (a < b) return gcd(b, a);
  if (a % b == 0) return b;
  return gcd(b, a%b);
}
//筛法求素数
#define MX 10000
vector<int> primes;
bool np[MX + 1];

void init (int n = MX){
    for (int i = 2; i <= n; i++) {
        if (!np[i]) {
            primes.push_back(i);
            for (int j = i; j <= n / i; j++) // 避免溢出的写法
                np[i * j] = true;
        }
    }
}
//快速幂
long long binpow(long long a, long long b) {
  long long res = 1;
  while (b > 0) {
    if (b & 1) res = res * a;
    a = a * a;
    b >>= 1;
  }
  return res;
}
long long binpow(long long a, long long b, int mod) {
  long long res = 1;
  while (b > 0) {
    if (b & 1) res = res * a % mod;
    a = a * a % mod;
    b >>= 1;
  }
  return res;
}
//组合数
long long int combi(int n,int m){//求组合数的函数
    long long int cnt = 1;
    for(int i = 0; i < m; i++){
        cnt *= n - i;
        cnt /= i + 1;
    }
    return cnt;
}
//卡特兰数
//应用:在n个元素出栈的可能性次数;二叉树的中序序列已知,求二叉树的种类的个数;n个节点的二叉树有多少种。
/*
公式一
递归公式
h(0)=h(1)=1
h(n)=h(0)∗h(n−1)+h(1)∗h(n−2)+...+h(n−1)∗h(0)(n>=2)
如果我们用这个公式显然我们要使用递归算法,那么数据一大就在时空上很麻烦
*/
long long int catalan(int n) {
	if (n <= 1) return 1;
	long long int ret = 0;
	for (int i = 0; i < n; i++) {
		ret += catalan(i) * catalan(n-1-i);
	}
	return ret;
}

/*
公式二
递推公式
h(n)=h(n−1)∗(4∗n−2)/(n+1)
这个公式应用递推,看上起十分和善
但对大数据呢?
我们注意到大数据的时候h(n)会很大,这时候题目一般会让你对某素数取模(当然你可以打高精度(划掉))
但你在取模过程中难保一个h(n)%mod=0
那么根据公式下面所有的数都会等于0,于是你就愉快的WA了
*/
long long int catalan(int n)
{
	long long int f[25]{0};
	f[0] = 1;
	for (int i = 1; i <= n; i++) f[i] = f[i - 1] * (4 * i - 2) / (i + 1);
	return f[n];
}

/*
公式三
组合数公式1
h(n)=C(2n,n)/(n+1)(n=0,1,2,...)

卡特兰数可以与组合数联系起来,得到上面的公式
而组合数就是一个杨辉三角,可以递推得到(这个不属于这道题的讨论范围我假装你们都会(逃))
但我们发现对于大数据你要取模,而对于除法你是没办法用膜的性质的(当然你可以应用逆元(划掉)),所以造成了麻烦

公式四
组合数公式2
h(n)=c(2n,n)−c(2n,n−1)(n=0,1,2,...)

与组合数公式1不同这个是两个组合数的减法
减法是可以用膜的性质的,于是你可以愉快的AC了。
*/

统计

并查集

struct UF{
    int n;
    int cnt;
    vector<int> fa;
    vector<int> sz;
    UF(int _n) : n(_n), cnt(_n), fa(_n), sz(_n, 1) {
        iota(fa.begin(), fa.end(), 0);
    }
    int find(int x) {
        return fa[x] == x ? x : fa[x] = find(fa[x]);
    }
    bool merge(int x, int y) {
        int fx = find(x);
        int fy = find(y);
        if (fx == fy) return false;
        if (sz[fx] < sz[fy]) swap(fx, fy);
        fa[fy] = fx;
        sz[fx] += sz[fy];
        cnt--;
        return true;
    }
    bool connected(int x, int y) {
        int fx = find(x);
        int fy = find(y);
        return (fx == fy);
    }
};

树状数组

struct BIT {
    vector<long long> tree;
    BIT(int n): tree(n+1){}
    static constexpr int lowbit(int x) {
        return x & (-x);
    }
    void update(int index, int delta) {
        // x是从1开始的下标
        for (int i = index; i < tree.size(); i += lowbit(i)) {
            tree[i] += delta;
        }
    }
    //查询区间(0,x)的和
    long long query(int x) {
        long long res = 0;
        // 从右到左查询,最小到1,不能等于0
        for (int i = x; i > 0; i -= lowbit(i)) {
            res += tree[i];
        }
        return res;
    }
    // 查询区间[l, r]的和
    long long query(int l, int r) {
        return query(r+1) - query(l);
    }
};

MISC

二分法

版本1
当我们将区间[l, r]划分成[l, mid][mid + 1, r]时,其更新操作是r = mid或者l = mid + 1;计算mid时不需要加1。

int bsearch_1(int l, int r)
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
    return l;
}

版本2
当我们将区间[l, r]划分成[l, mid-1][mid, r]时,其更新操作是r = mid - 1或者l = mid;此时为了防止死循环,计算mid时需要加1。

int bsearch_2(int l, int r)
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}
posted @ 2022-06-19 23:09  算你牛  阅读(44)  评论(0)    收藏  举报