算法整理(C++)

并查集

(1).种类

    
int find(int x)
{
    if (x != fa[x])
        fa[x] = find(fa[x]);
    return fa[x];
} // 查询
void add(int x, int y)
{
    int r1 = find(fa[x]), r2 = find(fa[y]);
    fa[r1] = r2;
} // 合并
void solve()
{
    int n, k;
    cin >> n >> k;
    int ans = 0;
    for (int i = 1; i <= 3 * n; ++i)
    {
        fa[i] = i;
    }

​ (2).带权

    auto find = [&] (auto find, int x) -> int{
        if(fa[x] != x){
            int t = find(find, fa[x]);
            d[x] = d[fa[x]] + d[x];
            fa[x] = t;
        }
        return fa[x];
    };
    auto add = [&] (int u, int v, int c) -> void {
        int uu = find(find, u), vv = find(find, v);
        fa[uu] = vv;
        d[uu] = ((d[v] - d[u] - c) % 3 + 3) % 3;
    };

ST表

void init()
{
    for (int j = 1; j <= 20; ++j)
    {
        for (int i = 1; (1 << j) - 1 + i <= n; ++i)
        {
            vec[i][j] = max(vec[i][j - 1], vec[i + (1 << j-1)][j - 1]);
        }
    }
}
int query(int le, int rg)
{
    int len = log2(rg - le + 1);
    int ret = max(vec[le][len], vec[rg - (1 << len) + 1][len]);
    return ret;
}

KMP

vector<int> prefix_function(string s)
{
    int n = (int)s.length();
    vector<int> pi(n);
    for (int i = 1; i < n; i++)
    {
        int j = pi[i - 1];
        while (j > 0 && s[i] != s[j])
            j = pi[j - 1];
        if (s[i] == s[j])
            j++;
        pi[i] = j;
    }
    return pi;
}
vector<int> find_occurrences(string text, string pattern)
{
    string cur = pattern + '#' + text;
    int sz1 = text.size(), sz2 = pattern.size();
    vector<int> v;
    vector<int> lps = prefix_function(cur);
    for (int i = sz2 + 1; i <= sz1 + sz2; i++)
    {
        if (lps[i] == sz2)
            v.push_back(i - 2 * sz2);
    }
    return v;
}

树状数组

//单点查询
vector<int> tr;
int n; 
int lowbit(int x)
{
    return x & -x;
}
void add(int x, int k)
{
    while (x <= n)
    {
        tr[x] += k;
        x += lowbit(x);
    }
}
int getsum(int x)
{
    int ret = 0;
    while (x)
    {
        ret += tr[x];
        x -= lowbit(x);
    }
    return ret;
}

LCA

void dfs(int u)
{
    vis[u] = 1;
    for (auto i : e[u]){
        if (vis[i] != 1){
            dep[i] = dep[u] + 1;
            fa[0][i] = u;
            dfs(i);
        }
    }
} // 初始化
int LCA(int x, int y)//x,y两节点的最近公共祖先
{
    if (dep[x] < dep[y])
        swap(x, y);
    while (dep[x] > dep[y])
    {
        x = fa[(int)log2(dep[x] - dep[y])][x];
    }
    if (x == y)
    {
        return x;
    }
    for (int i = (int)log2(dep[x]); i >= 0; --i)
    {
        if (fa[i][x] != fa[i][y])
        {
            x = fa[i][x];
            y = fa[i][y];
        }
    }
    return fa[0][x];
}

线段树


const int maxsize = 1e7 + 9;
int n, m, mod;
struct node
{
    int l, r, add, mul, sum;
} s[maxsize * 4];
int a[maxsize];
void updata(int pos)
{
    s[pos].sum = (s[pos << 1].sum + s[pos << 1 | 1].sum) % mod;
    return;
}
void pushdown(int pos)
{ // 下传标记
    // sum维护
    s[pos << 1].sum = (s[pos << 1].sum * s[pos].mul + s[pos].add * (s[pos << 1].r - s[pos << 1].l + 1)) % mod;
    s[pos << 1 | 1].sum = (s[pos << 1 | 1].sum * s[pos].mul + s[pos].add * (s[pos << 1 | 1].r - s[pos << 1 | 1].l + 1)) % mod;
    // mul维护
    s[pos << 1].mul = (s[pos << 1].mul * s[pos].mul) % mod;
    s[pos << 1 | 1].mul = (s[pos << 1 | 1].mul * s[pos].mul) % mod;
    // add维护
    s[pos << 1].add = (s[pos << 1].add * s[pos].mul + s[pos].add) % mod;
    s[pos << 1 | 1].add = (s[pos << 1 | 1].add * s[pos].mul + s[pos].add) % mod;
    // 重置add,mul
    s[pos].add = 0;
    s[pos].mul = 1;
    return;
}
void build(int pos, int l, int r)
{ // 建树
    s[pos].l = l;
    s[pos].r = r;
    s[pos].mul = 1;

    if (l == r)
    {
        s[pos].sum = a[l] % mod;
        return;
    }

    int mid = (l + r) >> 1;
    build(pos << 1, l, mid);
    build(pos << 1 | 1, mid + 1, r);
    updata(pos);
    return;
}
void ChangeMul(int pos, int x, int y, int k)
{ // 区间乘法
    if (x <= s[pos].l && s[pos].r <= y)
    {
        s[pos].add = (s[pos].add * k) % mod;
        s[pos].mul = (s[pos].mul * k) % mod;
        s[pos].sum = (s[pos].sum * k) % mod;
        return;
    }

    pushdown(pos);
    int mid = (s[pos].l + s[pos].r) >> 1;
    if (x <= mid)
        ChangeMul(pos << 1, x, y, k);
    if (y > mid)
        ChangeMul(pos << 1 | 1, x, y, k);
    updata(pos);
    return;
}

void ChangeAdd(int pos, int x, int y, int k)
{ // 区间加法
    if (x <= s[pos].l && s[pos].r <= y)
    {
        s[pos].add = (s[pos].add + k) % mod;
        s[pos].sum = (s[pos].sum + k * (s[pos].r - s[pos].l + 1)) % mod;
        return;
    }

    pushdown(pos);
    int mid = (s[pos].l + s[pos].r) >> 1;
    if (x <= mid)
        ChangeAdd(pos << 1, x, y, k);
    if (y > mid)
        ChangeAdd(pos << 1 | 1, x, y, k);
    updata(pos);
    return;
}
int AskRange(int pos, int x, int y)
{ // 区间询问
    if (x <= s[pos].l && s[pos].r <= y)
    {
        return s[pos].sum;
    }

    pushdown(pos);
    int val = 0;
    int mid = (s[pos].l + s[pos].r) >> 1;
    if (x <= mid)
        val = (val + AskRange(pos << 1, x, y)) % mod;
    if (y > mid)
        val = (val + AskRange(pos << 1 | 1, x, y)) % mod;
    return val;
}

//--build()初始化 --

线性筛

vector<int> not_pri;
vector<int> pri;
//初始化not_pri
void get_pri(int n)
{
    for (int i = 2; i <= n;++i)
    {
        if(not_pri[i] == 0)
        {
            pri.push_back(i);
        }
        for(auto j:pri)
        {
            if(j*i >n)
                break;
            not_pri[i * j] = 1;
            if(i%j == 0)
                break;
        }
    }
}

Manacher

vector<int> d;
string read_s(string s)
{
    string ret;
    ret += '#';
    for (int i = 0; i < s.size(); ++i)
    {
        ret += s[i];
        ret += '#';
    }
    return ret;
}
int check(char a, char b)
{
    return a == b ? 1 : 0;
}
void Manacher(string &s)
{
    for (int i = 0, l = 0, r = -1; i < s.size(); ++i)
    {
        int k = (i > r) ? 1 : min(d[l + r - i], r - i + 1);
        while (i - k >= 0 && i + k < s.size() && s[i - k] == s[i + k])
        {
            k++;
        }
        d[i] = k--;
        if (i + k > r)
        {
            r = i + k;
            l = i - k;
        }
    }
}

Exgcd

// 裴蜀定理: ax+by = c 有解的充要条件 gcd(a,b)|c;
int exgcd(int a, int b, int &x, int &y)
{//ax = 1(mod b) ---> x = ((x%b)+b)%b 化为正数
    if (!b)
    {
        x = 1;
        y = 0;
        return a;
    }
    int gcd = exgcd(b, a % b, y, x);
    y -= (a / b) * x;
    return gcd;
}

逆元

//1.exgcd
//2. 线性求1~n的逆元
int inv[10000007];
void f_inv(int n, int p)
{
    for (int i = 2; i <= n; ++i)
    {
        inv[i] = (p - p / i) * inv[p % i] % p;
    }
}
    int n, p, k;
    n = read(), p = read(), k = read();
    vector<int> a(n + 1), s(n + 1), sv(n + 1);
    s[0] = 1;
    for (int i = 1; i <= n; ++i)
    {
        a[i] = read();
        s[i] = (s[i - 1] * a[i]) % p;
    }
    int cur;
    exgcd(s[n], p, sv[n], cur);
    sv[n] = (sv[n] % p + p) % p;
    for (int i = n - 1; i >=1; --i)
    {
        sv[i] = sv[i + 1] * a[i + 1] % p;
    }
    int ans = 0, nowk = k;
    for (int i = 1; i <= n; ++i)
    {
        (ans += nowk * s[i - 1] % p * sv[i] % p) %= p;
        (nowk *= k) %= p;
    }
    cout << ans << endl;
}// 求任意n个数的逆元

快速幂

long long qpow(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 qpow(long long a, long long b, long long m) {
  a %= m;
  long long res = 1;
  while (b > 0) {
    if (b & 1) res = res * a % m;
    a = a * a % m;
    b >>= 1;
  }
  return res;
}

快速乘

long long binmul(long long a, long long b, long long m) {
  unsigned long long c =
      (unsigned long long)a * b -
      (unsigned long long)((long double)a / m * b + 0.5L) * m;
  if (c < m) return c;
  return c + m;
}

//更快

卡特兰数 ---->坐标系上y=x以下

image-20240224160007441 image-20240221172329618
#include <iostream>
using namespace std;
int n;
long long f[25];

int main() {
  f[0] = 1;
  cin >> n;
  for (int i = 1; i <= n; i++) f[i] = f[i - 1] * (4 * i - 2) / (i + 1);
  // 这里用的是常见公式2
  cout << f[n] << endl;
  return 0;
}

高精

1.乘

void mul(int a[], int b[], int c[]) {
  clear(c);

  for (int i = 0; i < LEN - 1; ++i) {
    // 这里直接计算结果中的从低到高第 i 位,且一并处理了进位
    // 第 i 次循环为 c[i] 加上了所有满足 p + q = i 的 a[p] 与 b[q] 的乘积之和
    // 这样做的效果和直接进行上图的运算最后求和是一样的,只是更加简短的一种实现方式
    for (int j = 0; j <= i; ++j) c[i] += a[j] * b[i - j];

    if (c[i] >= 10) {
      c[i + 1] += c[i] / 10;
      c[i] %= 10;
    }
  }
}
void mul_short(int a[], int b, int c[]) {
  clear(c);

  for (int i = 0; i < LEN - 1; ++i) {
    // 直接把 a 的第 i 位数码乘以乘数,加入结果
    c[i] += a[i] * b;

    if (c[i] >= 10) {
      // 处理进位
      // c[i] / 10 即除法的商数成为进位的增量值
      c[i + 1] += c[i] / 10;
      // 而 c[i] % 10 即除法的余数成为在当前位留下的值
      c[i] %= 10;
    }
  }
}

2.除

// 被除数 a 以下标 last_dg 为最低位,是否可以再减去除数 b 而保持非负
// len 是除数 b 的长度,避免反复计算
bool greater_eq(int a[], int b[], int last_dg, int len) {
  // 有可能被除数剩余的部分比除数长,这个情况下最多多出 1 位,故如此判断即可
  if (a[last_dg + len] != 0) return true;
  // 从高位到低位,逐位比较
  for (int i = len - 1; i >= 0; --i) {
    if (a[last_dg + i] > b[i]) return true;
    if (a[last_dg + i] < b[i]) return false;
  }
  // 相等的情形下也是可行的
  return true;
}

void div(int a[], int b[], int c[], int d[]) {
  clear(c);
  clear(d);

  int la, lb;
  for (la = LEN - 1; la > 0; --la)
    if (a[la - 1] != 0) break;
  for (lb = LEN - 1; lb > 0; --lb)
    if (b[lb - 1] != 0) break;
  if (lb == 0) {
    puts("> <");
    return;
  }  // 除数不能为零

  // c 是商
  // d 是被除数的剩余部分,算法结束后自然成为余数
  for (int i = 0; i < la; ++i) d[i] = a[i];
  for (int i = la - lb; i >= 0; --i) {
    // 计算商的第 i 位
    while (greater_eq(d, b, i, lb)) {
      // 若可以减,则减
      // 这一段是一个高精度减法
      for (int j = 0; j < lb; ++j) {
        d[i + j] -= b[j];
        if (d[i + j] < 0) {
          d[i + j + 1] -= 1;
          d[i + j] += 10;
        }
      }
      // 使商的这一位增加 1
      c[i] += 1;
      // 返回循环开头,重新检查
    }
  }
}

3.加

void add(int a[], int b[], int c[]) {
  clear(c);

  // 高精度实现中,一般令数组的最大长度 LEN 比可能的输入大一些
  // 然后略去末尾的几次循环,这样一来可以省去不少边界情况的处理
  // 因为实际输入不会超过 1000 位,故在此循环到 LEN - 1 = 1003 已经足够
  for (int i = 0; i < LEN - 1; ++i) {
    // 将相应位上的数码相加
    c[i] += a[i] + b[i];
    if (c[i] >= 10) {
      // 进位
      c[i + 1] += 1;
      c[i] -= 10;
    }
  }
}

4.减

void sub(int a[], int b[], int c[]) {
  clear(c);

  for (int i = 0; i < LEN - 1; ++i) {
    // 逐位相减
    c[i] += a[i] - b[i];
    if (c[i] < 0) {
      // 借位
      c[i + 1] -= 1;
      c[i] += 10;
    }
  }
}

Lucas

int qpow(int x, int k, int p)
{
    int ret = 1;
    while (k)
    {
        if (k & 1)
        {
            ret = ret * x % p;
        }
        x = x * x % p;
        k >>= 1;
    }
    return ret;
}// 快速幂
int getans(int x, int y, int p)
{
    if (y > x)
    {
        return 0;
    }
    int ret = 1;
    for (int i = 1; i <= y; ++i)
    {
        ret = ret * qpow(i, p - 2, p) % p;
    }
    for (int i = x; i >= x - y + 1; --i)
    {
        ret = ret * i % p;
    }
    return ret;
}//求x取y模p,m,n较小时
int lucas(int x, int y, int p)
{
    if (x < p && y < p)
    {
        return getans(x, y, p);
    }
    return lucas(x / p, y / p, p) * getans(x % p, y % p, p) % p;
    //
}//求x取y模p,m,n较大时

Nim游戏

void solve()
{
    int n;
    cin >> n;
    int sum ;
    cin >> sum;
    for (int i = 1; i < n;++i)
    {
        int x;
        cin >> x;
        sum ^= x;
    }
    if(sum != 0)
    {
        cout << "Yes" << endl;
    }
    else
    {
        cout << "No" << endl;
    }
}//考虑异或
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值