模板 v0.2

数学

exgcd

void exgcd(ll a, ll b, ll &x, ll &y)
{
    if (!b)
    {
        x = 1, y = 0;
        return;
    }
    exgcd(b, a % b, x, y);
    int t = x;
    x = y;
    y = t - a / b * y;
}

FFT

//FFT求卷积
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#define ll long long
#define N 4000009
#define reg register
#define pi 3.141592653589793
using namespace std;

struct complex
{
    double x, y;
    complex(double x = 0, double y = 0) :
        x(x), y(y) {}

    inline complex operator+(const complex b) const
    {
        return complex(x + b.x, y + b.y);
    }

    inline complex operator-(const complex b) const
    {
        return complex(x - b.x, y - b.y);
    }

    inline complex operator*(const complex b) const
    {
        complex res;
        res.x = x * b.x - y * b.y;
        res.y = x * b.y + y * b.x;
        return res;
    }
};

inline void read(int &x);
void print(int x);
inline void FFT(complex *a, int type, int lim);

int n, m;
complex F[N];
int rev[N];

signed main()
{
    int qwq, t, lim = 1, l = -1;
    read(n), read(m);
    for (reg int i = 0; i <= n; ++i) read(t), F[i].x = t;
    for (reg int i = 0; i <= m; ++i) read(t), F[i].y = t; //把G(x)放到F(x)的虚部上
    t = n + m;
    n = max(n, m);
    while (lim <= (n << 1))
    {
        lim <<= 1;
        ++l;
    }
    for (reg int i = 1; i <= lim; ++i)
        rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << l);
    FFT(F, 1, lim);
    for (reg int i = 0; i <= lim; ++i)
        F[i] = F[i] * F[i]; //求出F(x)^2
    FFT(F, -1, lim);
    for (reg int i = 0; i <= t; ++i)
    {
        qwq = F[i].y / 2 + 0.5; //虚部取出来除2,注意要+0.5,否则精度会有问题
        print(qwq);
        putchar(' ');
    }
    return 0;
}

inline void FFT(complex *a, int type, int lim)
{ //没什么好说的,FFT的模板
    for (reg int i = 1; i <= lim; ++i)
    {
        if (i >= rev[i]) continue;
        swap(a[i], a[rev[i]]);
    }
    reg complex rt, w, x, y;
    for (reg int mid = 1; mid < lim; mid <<= 1)
    {
        reg int r = mid << 1;
        rt = complex(cos(pi / mid), type * sin(pi / mid));
        for (reg int j = 0; j < lim; j += r)
        {
            w = complex(1, 0);
            for (reg int k = 0; k < mid; ++k)
            {
                x = a[j | k];
                y = w * a[j | k | mid];
                a[j | k] = x + y;
                a[j | k | mid] = x - y;
                w = w * rt;
            }
        }
    }
    if (type == 1) return;
    for (reg int i = 0; i <= lim; ++i)
    {
        a[i].y = a[i].y / lim;
        a[i].x = a[i].x / lim;
    }
}

inline void read(int &x)
{
    x = 0;
    char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9')
    {
        x = (x << 3) + (x << 1) + (c ^ 48);
        c = getchar();
    }
}

void print(int x)
{
    if (x > 9) print(x / 10);
    putchar(x % 10 + '0');
}

NTT

//NTT求卷积
#include <cstdio>
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
#define swap(x, y) x ^= y, y ^= x, x ^= y
#define LL long long
const int MAXN = 3 * 1e6 + 10, P = 998244353, G = 3, Gi = 332748118;
char buf[1 << 21], *p1 = buf, *p2 = buf;
inline int read()
{
    char c = getchar();
    int x = 0, f = 1;
    while (c < '0' || c > '9')
    {
        if (c == '-') f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
int N, M, limit = 1, L, r[MAXN];
LL a[MAXN], b[MAXN];
inline LL fastpow(LL a, LL k)
{
    LL base = 1;
    while (k)
    {
        if (k & 1) base = (base * a) % P;
        a = (a * a) % P;
        k >>= 1;
    }
    return base % P;
}
inline void NTT(LL *A, int type)
{
    for (int i = 0; i < limit; i++)
        if (i < r[i]) swap(A[i], A[r[i]]);
    for (int mid = 1; mid < limit; mid <<= 1)
    {
        LL Wn = fastpow(type == 1 ? G : Gi, (P - 1) / (mid << 1));
        for (int j = 0; j < limit; j += (mid << 1))
        {
            LL w = 1;
            for (int k = 0; k < mid; k++, w = (w * Wn) % P)
            {
                int x = A[j + k], y = w * A[j + k + mid] % P;
                A[j + k] = (x + y) % P;
                A[j + k + mid] = (x - y + P) % P;
            }
        }
    }
}
int main()
{
    N = read();
    M = read();
    for (int i = 0; i <= N; i++) a[i] = (read() + P) % P;
    for (int i = 0; i <= M; i++) b[i] = (read() + P) % P;
    while (limit <= N + M) limit <<= 1, L++;
    for (int i = 0; i < limit; i++) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (L - 1));
    NTT(a, 1);
    NTT(b, 1);
    for (int i = 0; i < limit; i++) a[i] = (a[i] * b[i]) % P;
    NTT(a, -1);
    LL inv = fastpow(limit, P - 2);
    for (int i = 0; i <= N + M; i++)
        printf("%d ", (a[i] * inv) % P);
    return 0;
}

线性求逆元

inv[1] = 1;
for (int i = 2; i <= n; ++i) 
{
  inv[i] = (long long)(p - p / i) * inv[p % i] % p;
}

线性求n个数逆元

s[0] = 1;
for (int i = 1; i <= n; ++i) s[i] = s[i - 1] * a[i] % p;
sv[n] = qpow(s[n], p - 2);
// 当然这里也可以用 exgcd 来求逆元,视个人喜好而定.
for (int i = n; i >= 1; --i) sv[i - 1] = sv[i] * a[i] % p;
for (int i = 1; i <= n; ++i) inv[i] = sv[i] * s[i - 1] % p;

自适应辛普森积分

double simpson(double l, double r) {
  double mid = (l + r) / 2;
  return (r - l) * (f(l) + 4 * f(mid) + f(r)) / 6;  // 辛普森公式
}
double asr(double l, double r, double eqs, double ans, int step) {
  double mid = (l + r) / 2;
  double fl = simpson(l, mid), fr = simpson(mid, r);
  if (abs(fl + fr - ans) <= 15 * eqs && step < 0)
    return fl + fr + (fl + fr - ans) / 15;  // 足够相似的话就直接返回
  return asr(l, mid, eqs / 2, fl, step - 1) +
         asr(mid, r, eqs / 2, fr, step - 1);  // 否则分割成两段递归求解
}
double calc(double l, double r, double eps) {
  return asr(l, r, eps, simpson(l, r), 12);
}

二次剩余(cipolla)

给出 N,p,求解方程 $x^2 \equiv N(\bmod ~p) $

struct cp
{
    ll x, y;
    cp(ll _x = 0, ll _y = 0) { x = _x, y = _y; }
    cp operator*(cp b) const
    {
        cp res;
        res.x = ((x * b.x) % mod + ((y * b.y) % mod) * fuck % mod) % mod;
        res.y = (x * b.y + y * b.x) % mod;
        return res;
    }
};
ll fp(ll a, ll b)
{
    ll c = 1;
    while (b > 1)
    {
        if (b & 1) c *= a, c %= mod;
        a *= a, b >>= 1, a %= mod;
    }
    return (a * c) % mod;
}
cp fp1(cp a, ll b)
{
    cp c = {1, 0};
    while (b > 1)
    {
        if (b & 1) c = c * a;
        a = a * a, b >>= 1;
    }
    return a * c;
}
ll cipolla(ll n)
{
    srand(time(0));
    n %= mod;
    ll a;
    while (1)
    {
        a = rand() % mod;
        fuck = (a * a - n + mod) % mod;
        if (fp(fuck, (mod - 1) / 2) == mod - 1) break;
    }
    return fp1(cp(a, 1), (mod + 1) / 2).x;
}

常用泰勒展开

\[\large e^x=1+x+\frac{x^2}{2!}+\frac{x^3}{3!}+\dots \\ \large sin(x)=x-\frac{x^3}{3!}+\frac{x^5}{5!}-\dots \\ \large cos(x)=1-\frac{x^2}{2!}+\frac{x^4}{4!}-\dots \\ \large arcsin(x)=x+\frac{x^3}{3!} \\ \large \frac{1}{1-x}=1+x+x^2+x^3+\dots \\ \large \frac{1}{1+x}=1-x+x^2-x^3+\dots \\ \large ln(1+x)=x-\frac{x^2}{2}+\frac{x^3}{3}-\frac{x^4}{4}+\dots \\ \large \frac{1}{1+x^2}=1-x^2+x^4-x^6+\dots \\ \large tan(x)=x+\frac{x^3}{3} \\ \large arctan(x)=x-\frac{x^3}{3}+\frac{x^5}{5}-\frac{x^7}{7}+\dots \]

BSGS

给定一个质数 \(p\),以及一个整数 %b%,一个整数 \(n\),现在要求你计算一个最小的非负整数 \(l\),满足 \(b^l \equiv n \pmod p\)

ll bsgs(ll a, ll b, ll p)
{
    if (a == 0)
    {
        if (b == 0) return 1;
        return -1;
    }
    a %= p, b %= p;
    mp.clear();
    ll t = sqrt(p), a1 = fp(a, t), x = 1;
    for (int i = 0; i < t; i++)
    {
        mp[x] = i;
        x *= a1, x %= p;
    }
    x = b;
    for (int j = 0; j < t; j++)
    {
        ll val = -1;
        if (mp.find(x) != mp.end()) val = mp[x];
        if (val > 0 && val * t - j >= 0) return val * t - j;
        x *= a, x %= p;
    }
    return -1;
}

特征方程求通项公式

设数列 \(\{x_n\}\)的前两项 \(x_1\) , \(x_2\) 已知,且 \(x_{n+1}=px_n+qx_{n-1}\),则称方程 \(x^2-px-q=0\)为该数列的特征方程。该方程若有两个根 \(a\) , \(b\) ,则称这两个根为该数列的特征根。

因此设数列 \(x_n=\alpha \cdot a^{n-1}+\beta \cdot b^{n-1}\)

由

\[\large \left \{\begin{align} & x_1=\alpha + \beta\\ & x_2=\alpha \cdot a+\beta \cdot b\\ \end{align} \right. \]

解得

\[\large \left \{\begin{align} & \alpha=\frac{x_2-bx_1}{a-b} \\ & \beta=\frac{x_2-ax_1}{b-a} \\ \end{align} \right. \]

因此数列的通项公式为 \(\large x_n=\frac{x_2-bx_1}{a-b}\cdot a^{n-1}+\frac{x_2-ax_1}{b-a}\cdot b^{n-1}\)

中国剩余定理(crt)

void exgcd(ll a, ll b, ll &x, ll &y)
{
    if (!b)
    {
        x = 1, y = 0;
        return;
    }
    exgcd(b, a % b, x, y);
    int t = x;
    x = y;
    y = t - a / b * y;
}
ll inv(ll a,ll p1)
{
    ll x,k;
    exgcd(a,p1,x,k);
    x=(x+p1)%p1;
    return x;
}
ll crt(int n)
{
    ll ans=0,lc=1,w,m1;
    for(int i=0;i<n;i++) lc*=p[i];
    for(int i=0;i<n;i++)
    {
        w=inv(lc/p[i],p[i]);
        m1=w*r[i];
        ans+=m1*(lc/p[i]);
        ans%=lc;
    }
    return ans;
}

扩展中国剩余定理

ll c[maxn], p[maxn]; //x=c (mod p)
void exgcd(ll a, ll b, ll &x, ll &y)
{
    if (!b)
    {
        x = 1, y = 0;
        return;
    }
    exgcd(b, a % b, x, y);
    ll t = x;
    x = y;
    y = t - a / b * y;
}
ll slowm(ll a, ll b, ll p1)
{
    if (a == 0 || b == 0) return 0;
    ll c1 = 0;
    while (b > 1)
    {
        if (b & 1) c1 += a, c1 %= p1;
        a += a, b >>= 1, a %= p1;
    }
    return (a + c1) % p1;
}
ll excrt(int n)
{
    ll x, y;
    ll p1 = p[0];
    ll ans = c[0];
    for (int i = 1; i < n; i++)
    {
        ll cc = (c[i] - ans % p[i] + p[i]) % p[i];
        ll g = __gcd(p1, p[i]);
        if (cc % g != 0)
            return -1;
        exgcd(p1, p[i], x, y);
        ll p2 = p[i] / g;
        x = slowm(x, cc / g, p2);
        ans += x * p1;
        p1 *= p2;
        ans = (ans % p1 + p1) % p1;
    }
    return (ans % p1 + p1) % p1;
}

miller rabin判素数

int miller_rabin(ll P)
{
    int Test[10] = {2, 3, 5, 7, 11, 13, 17, 19};
    if (P == 1) return 0;
    int t = P - 1, k = 0;
    while (!(t & 1)) k++, t >>= 1;
    for (int i = 0; i < 8; i++)
    {
        if (P == Test[i]) return 1;
        ll a = fp(Test[i], t, P), nxt = a;
        for (int j = 1; j <= k; j++)
        {
            nxt = (a * a) % P;
            if (nxt == 1 && a != 1 && a != P - 1) return 0;
            a = nxt;
        }
        if (a != 1) return 0;
    }
    return 1;
}

矩阵

template <int row, int col>
struct Matrix
{
    int r, c;
    long long ele[row][col];
    Matrix() { throw "Please set row and column!"; }
    Matrix(int a, int b) : r(a), c(b) { memset(ele, 0, sizeof(ele)); }
    long long &operator()(int a, int b) { return ele[a][b]; }
    Matrix &operator+=(Matrix oth) { return *this = *this + oth; }
    Matrix &operator-=(Matrix oth) { return *this = *this - oth; }
    Matrix &operator*=(Matrix oth) { return *this = *this * oth; }
};
template <int m, int n>
Matrix<m, n> operator+(Matrix<m, n> m1, Matrix<m, n> m2)
{
    Matrix<m, n> ret;
    for (int i = 0; i < m1.r; i++)
        for (int j = 0; j < m1.c; j++)
            ret(i, j) = m1(i, j) + m2(i, j);
    return ret;
}
template <int m, int n>
Matrix<m, n> operator-(Matrix<m, n> m1, Matrix<m, n> m2)
{
    Matrix<m, n> ret;
    for (int i = 0; i < m1.r; i++)
        for (int j = 0; j < m1.c; j++)
            ret(i, j) = m1(i, j) + m2(i, j);
    return ret;
}
template <int m, int n, int p>
Matrix<m, p> operator*(Matrix<m, n> m1, Matrix<n, p> m2) //普通乘法
{
    Matrix<m, p> ret(m1.r, m2.c);
    for (int i = 0; i < m1.r; i++)
        for (int k = 0; k < m1.c; k++)
            for (int j = 0; j < m2.c; j++)
                ret(i, j) += m1(i, k) * m2(k, j);
    return ret;
}
template <int m, int n>
Matrix<m, n> operator^(Matrix<m, n> mat, long long k) //快速幂
{
    Matrix<m, n> ans = mat;
    for (k--; k; mat *= mat, k >>= 1)
        if (k & 1)
            ans *= mat;
    return ans;
}
template <int m, int n, int p>
Matrix<m, p> mulmod(Matrix<m, n> m1, Matrix<n, p> m2, int mod) //乘加取模
{
    Matrix<m, p> ret(m1.r, m2.c);
    for (int i = 0; i < m1.r; i++)
        for (int k = 0; k < m1.c; k++)
            for (int j = 0; j < m2.c; j++)
                ret(i, j) = (ret(i, j) + m1(i, k) * m2(k, j) % mod) % mod;
    return ret;
}
template <int m, int n>
Matrix<m, n> qpowmod(Matrix<m, n> mat, long long k, int mod) //快速幂取模
{
    Matrix<m, n> ans = mat;
    for (k--; k; mat = mulmod(mat, mat, mod), k >>= 1)
        if (k & 1)
            ans = mulmod(ans, mat, mod);
    return ans;
}
template <int m, int n>
ostream &operator<<(ostream &os, Matrix<m, n> &mat)
{
    for (int i = 0; i < mat.r; i++)
    {
        for (int j = 0; j < mat.c; j++)
            os << mat(i, j) << ' ';
        os << endl;
    }
    return os;
}
template <int m, int n>
istream &operator>>(istream &is, Matrix<m, n> &mat)
{
    for (int i = 0; i < mat.r; i++)
        for (int j = 0; j < mat.c; j++)
            is >> mat(i, j);
    return is;
}
const int maxn = 105;
int main()
{
    int n;
    long long k;
    const int p = 1e9 + 7;
    cin >> n >> k;
    Matrix<maxn, maxn> mat(n, n);
    cin >> mat;
    auto tmp = qpowmod(mat, k, p);
    cout << tmp;
    return 0;
}

高斯消元

const int MAXN = 105;
const double EPS = 1e-8;
struct Matrix
{
    int r,c;
    double ele[MAXN][MAXN];
    Matrix(int r,int c):r(r),c(c) { memset(ele,0,sizeof(ele)); }
    double &operator()(int r,int c) { return ele[r][c]; }
};
istream &operator>>(istream &is, Matrix &mat)
{
    for (int i=0;i<mat.r;i++)
        for (int j=0;j<mat.c;j++)
            is>>mat(i,j);
    return is;
}
ostream &operator<<(ostream &os, Matrix &mat)
{
    for(int i=0;i<mat.r;i++)
    {
        for(int j=0;j<mat.c;j++)
            os<<fixed<<setprecision(2)<<mat(i,j)<<' ';
        os<<endl;
    }
    return os;
}
bool gauss(Matrix &mat)
{
    for(int i=0;i<mat.r;i++)    //遍历行
    {
        int p = i;  //当前系数
        for(int j=i+1;j<mat.r;j++)  //遍历每行的当前位置
            if(abs(mat(p,i))<abs(mat(j,i)))
                p = j;
        if(abs(mat(p,i))<EPS) return false;
        if(p!=i) for(int j=0;j<mat.c;j++)
            swap(mat(i,j),mat(p,j));
        for(int j=i+1;j<mat.c;j++)
            mat(i,j)/=mat(i,i);
        for(int j=0;j<mat.r;j++)
        {
            if(i==j) continue;
            for(int k=i+1;k<mat.c;k++)
                mat(j,k)-=mat(j,i)*mat(i,k);
        }
    }
    return true;
}
void print(Matrix &mat)
{
    for(int i=0;i<mat.r;i++)
        cout<<fixed<<setprecision(2)<<mat(i,mat.c-1)<<endl;
}
int main(int argc, char const *argv[])
{
    int n;
    cin>>n;
    static Matrix mat(n,n+1);
    cin>>mat;
    if(gauss(mat)) print(mat);
    else cout<<"No Solution"<<endl;
    return 0;
}

数据结构

trie树

struct trie {
  int nex[100000][26], cnt;
  bool exist[100000];  // 该结点结尾的字符串是否存在

  void insert(char *s, int l) {  // 插入字符串
    int p = 0;
    for (int i = 0; i < l; i++) {
      int c = s[i] - 'a';
      if (!nex[p][c]) nex[p][c] = ++cnt;  // 如果没有,就添加结点
      p = nex[p][c];
    }
    exist[p] = 1;
  }
  bool find(char *s, int l) {  // 查找字符串
    int p = 0;
    for (int i = 0; i < l; i++) {
      int c = s[i] - 'a';
      if (!nex[p][c]) return 0;
      p = nex[p][c];
    }
    return exist[p];
  }
};

树链剖分

const int maxn = 1e5 + 5;
const int maxm = maxn * 2;
struct E
{
    int to, next;
} Edge[maxm];
int tot, Head[maxn];
inline void AddEdge(int u, int v)
{
    Edge[tot] = (E){v, Head[u]};
    Head[u] = tot++;
    Edge[tot] = (E){u, Head[v]};
    Head[v] = tot++;
}
int mod;
int v[maxn];
int fa[maxn], dep[maxn], siz[maxn], son[maxn];
void dfs1(int u, int f)
{
    fa[u] = f;
    dep[u] = dep[f] + 1;
    siz[u] = 1;
    int maxsize = -1;
    for (int i = Head[u]; ~i; i = Edge[i].next)
    {
        int v = Edge[i].to;
        if (v == f)
            continue;
        dfs1(v, u);
        siz[u] += siz[v];
        if (siz[v] > maxsize)
        {
            maxsize = siz[v];
            son[u] = v;
        }
    }
}
int tim, dfn[maxn], top[maxn], w[maxn];
void dfs2(int u, int t)
{
    dfn[u] = ++tim;
    top[u] = t;
    w[tim] = v[u];
    if (!son[u])
        return;
    dfs2(son[u], t);
    for (int i = Head[u]; ~i; i = Edge[i].next)
    {
        int v = Edge[i].to;
        if (v == fa[u] || v == son[u])
            continue;
        dfs2(v, v);
    }
}
struct Node
{
    int l, r, f, val;
} sgt[maxn * 4];
inline int ls(int k) { return k << 1; }
inline int rs(int k) { return k << 1 | 1; }
inline void pushup(int k) { sgt[k].val = (sgt[ls(k)].val + sgt[rs(k)].val) % mod; }
inline void pushdown(int k)
{
    sgt[ls(k)].f += sgt[k].f;
    sgt[rs(k)].f += sgt[k].f;
    sgt[ls(k)].val += (sgt[ls(k)].r - sgt[ls(k)].l + 1) * sgt[k].f % mod;
    sgt[rs(k)].val += (sgt[rs(k)].r - sgt[rs(k)].l + 1) * sgt[k].f % mod;
    sgt[k].f = 0;
}
void build(int l, int r, int k = 1)
{
    sgt[k].l = l, sgt[k].r = r;
    if (l == r)
    {
        sgt[k].val = w[l] % mod;
        return;
    }
    int m = (l + r) >> 1;
    build(l, m, ls(k));
    build(m + 1, r, rs(k));
    pushup(k);
}
void modify(int x, int y, int z, int k = 1)
{
    int l = sgt[k].l, r = sgt[k].r;
    if (x <= l && y >= r)
    {
        sgt[k].f += z;
        sgt[k].val += (r - l + 1) * z;
        sgt[k].val %= mod;
        return;
    }
    if (sgt[k].f)
        pushdown(k);
    int m = (l + r) >> 1;
    if (x <= m)
        modify(x, y, z, ls(k));
    if (y > m)
        modify(x, y, z, rs(k));
    pushup(k);
}
int query(int x, int y, int k = 1)
{
    int l = sgt[k].l, r = sgt[k].r;
    if (x <= l && y >= r)
        return sgt[k].val;
    if (sgt[k].f)
        pushdown(k);
    int sum = 0, m = (l + r) >> 1;
    if (x <= m)
        sum += query(x, y, ls(k));
    if (y > m)
        sum += query(x, y, rs(k));
    return sum % mod;
}
void mchain(int x, int y, int z)
{
    z %= mod;
    while (top[x] != top[y])
    {
        if (dep[top[x]] < dep[top[y]])
            std::swap(x, y);
        modify(dfn[top[x]], dfn[x], z);
        x = fa[top[x]];
    }
    if (dep[x] > dep[y])
        std::swap(x, y);
    modify(dfn[x], dfn[y], z);
}
int qchain(int x, int y)
{
    int ret = 0;
    while (top[x] != top[y])
    {
        if (dep[top[x]] < dep[top[y]])
            std::swap(x, y);
        ret += query(dfn[top[x]], dfn[x]);
        x = fa[top[x]];
    }
    if (dep[x] > dep[y])
        std::swap(x, y);
    ret += query(dfn[x], dfn[y]);
    return ret % mod;
}
inline void mson(int x, int z)
{
    modify(dfn[x], dfn[x] + siz[x] - 1, z);
}
inline int qson(int x)
{
    return query(dfn[x], dfn[x] + siz[x] - 1);
}

ST表

//logg预处理log2
void build()
{
    for (int i = 1; i <= n; i++) stmax[i][0] = stmin[i][0] = a[i];
    for (int j = 1; j <= logg[n]; j++)
    {
        for (int i = 1; i + (1 << j) - 1 <= n; i++)
        {
            stmax[i][j] = max(stmax[i][j - 1], stmax[i + (1 << j - 1)][j - 1]);
            stmin[i][j] = min(stmin[i][j - 1], stmin[i + (1 << j - 1)][j - 1]);
        }
    }
}
int getmax(int l, int r)
{
    int len = r - l + 1;
    int x = logg[len];
    return max(stmax[l][x], stmax[r - (1 << x) + 1][x]);
}
int getmin(int l, int r)
{
    int len = r - l + 1;
    int x = logg[len];
    return min(stmin[l][x], stmin[r - (1 << x) + 1][x]);
}

莫队算法

block = n / sqrt(m);
sort(qq, qq + q, [](node a1, node a2) {
    if (a1.l / block == a2.l / block)
    {
        if ((a1.l / block) & 1) return a1.r < a2.r;
        return a1.r > a2.r;
    }
    return a1.l < a2.l;
}); //r++ l++ l-- r--

主席树

求区间第k大

#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 1e5;  // 数据范围
int tot, n, m;
int sum[(maxn << 5) + 10], rt[maxn + 10], ls[(maxn << 5) + 10],
    rs[(maxn << 5) + 10];
int a[maxn + 10], ind[maxn + 10], len;

inline int getid(const int &val) {  // 离散化
  return lower_bound(ind + 1, ind + len + 1, val) - ind;
}

int build(int l, int r) {  // 建树
  int root = ++tot;
  if (l == r) return root;
  int mid = l + r >> 1;
  ls[root] = build(l, mid);
  rs[root] = build(mid + 1, r);
  return root;  // 返回该子树的根节点
}

int update(int k, int l, int r, int root) {  // 插入操作
  int dir = ++tot;
  ls[dir] = ls[root], rs[dir] = rs[root], sum[dir] = sum[root] + 1;
  if (l == r) return dir;
  int mid = l + r >> 1;
  if (k <= mid)
    ls[dir] = update(k, l, mid, ls[dir]);
  else
    rs[dir] = update(k, mid + 1, r, rs[dir]);
  return dir;
}

int query(int u, int v, int l, int r, int k) {  // 查询操作
  int mid = l + r >> 1,
      x = sum[ls[v]] - sum[ls[u]];  // 通过区间减法得到左儿子中所存储的数值个数
  if (l == r) return l;
  if (k <= x)  // 若 k 小于等于 x ,则说明第 k 小的数字存储在在左儿子中
    return query(ls[u], ls[v], l, mid, k);
  else  // 否则说明在右儿子中
    return query(rs[u], rs[v], mid + 1, r, k - x);
}

inline void init() {
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= n; ++i) scanf("%d", a + i);
  memcpy(ind, a, sizeof ind);
  sort(ind + 1, ind + n + 1);
  len = unique(ind + 1, ind + n + 1) - ind - 1;
  rt[0] = build(1, len);
  for (int i = 1; i <= n; ++i) rt[i] = update(getid(a[i]), 1, len, rt[i - 1]);
}

int l, r, k;

inline void work() {
  while (m--) {
    scanf("%d%d%d", &l, &r, &k);
    printf("%d\n", ind[query(rt[l - 1], rt[r], 1, len, k)]);  // 回答询问
  }
}

int main() {
  init();
  work();
  return 0;
}

珂朵莉树

骗分。只要是有区间赋值操作的数据结构题都可以用来骗分。

节点保存方法

struct Node_t {
  int l, r;
  mutable int v;

  Node_t(const int &il, const int &ir, const int &iv) : l(il), r(ir), v(iv) {}

  inline bool operator<(const Node_t &o) const { return l < o.l; }
};

split

将包含x的区间分为\([l,x)和[x,r]\),返回指向后者的迭代器

auto split(int x) {
  if (x > n) return odt.end();
  auto it = --odt.upper_bound((Node_t){x, 0, 0});
  if (it->l == x) return it;
  int l = it->l, r = it->r, v = it->v;
  odt.erase(it);
  odt.insert(Node_t(l, x - 1, v));
  return odt.insert(Node_t(x, r, v)).first;
}

assign

区间赋值

void assign(int l, int r, int v) {
  auto itr = split(r + 1), itl = split(l);
  odt.erase(itl, itr);
  odt.insert(Node_t(l, r, v));
}

其他操作

珂朵莉树在进行求取区间左右端点操作时,必须先 split 右端点,再 split 左端点

void performance(int l, int r) {
  auto itr = split(r + 1), itl = split(l);
  for (; itl != itr; ++itl) {
    // Perform Operations here
  }
}

图论

SPFA判负环

bool spfa(int n, int s) {
  memset(dis, 63, sizeof(dis));
  dis[s] = 0, vis[s] = 1;
  q.push(s);
  while (!q.empty()) {
    int u = q.front();
    q.pop(), vis[u] = 0;
    for (auto ed : e[u]) {
      int v = ed.v, w = ed.w;
      if (dis[v] > dis[u] + w) {
        dis[v] = dis[u] + w;
        cnt[v] = cnt[u] + 1;  // 记录最短路经过的边数
        if (cnt[v] >= n) return false;
        // 在不经过负环的情况下,最短路至多经过 n - 1 条边
        // 因此如果经过了多于 n 条边,一定说明经过了负环
        if (!vis[v]) q.push(v), vis[v] = 1;
      }
    }
  }
  return true;
}

字符串

KMP

int nxt[M];
char s[M],p[M];

//获得next数组
void getnext(char *p,int len){
    int i,j;
    i=0,j=nxt[0]=-1;
    while(i<len){
        while(j!=-1&&p[i]!=p[j]) j=nxt[j];
        nxt[++i]=++j;
    }
}
//返回p在s中第一次出现的位置
void kmp(char *s,char *p){
    int len1,len2,i,j;
    i=j=0;
    len1=strlen(s);
    len2=strlen(p);
    getnext(p,len2);
    while(i<len1){
        while(j!=-1&&s[i]!=p[j]) j=nxt[j];
        i++,j++;
        if(j==len2)
            return i-len2+1;
    }
    return -1;
}

用途

在字符串中查找子串

字符串的周期

统计每个前缀的出现次数

其他

快读

inline int read()
{
    int s = 0, w = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-') w = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
    return s * w;
}

安全的unordered_map

struct custom_hash
{
    static uint64_t splitmix64(uint64_t x)
    {
        x += 0x9e3779b97f4a7c15;
        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
        x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
        return x ^ (x >> 31);
    }
    size_t operator()(uint64_t x) const
    {
        static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
        return splitmix64(x + FIXED_RANDOM);
    }
};
unordered_map<int, int, custom_hash> mp;

分数类

struct frac
{
    __int128 p,q;
    frac(){}
    frac(__int128 _p,__int128 _q)
    {
        if(_q<0) _p=-_p,_q=-_q;
        p=_p,q=_q;
    }
    frac operator +(const frac&rhs)
    {
        __int128 a,b;
        b=q*rhs.q;
        a=p*rhs.q+q*rhs.p;
        if(b==0) return frac(0,1);
        __int128 g=__gcd(a,b);
        a/=g;
        b/=g;
        return frac(a,b);
    }
    frac operator -(const frac&rhs)
    {
        __int128 a,b;
        b=q*rhs.q;
        a=p*rhs.q-q*rhs.p;
        if(b==0) return frac(0,1);
        __int128 g=__gcd(a,b);
        a/=g;
        b/=g;
        return frac(a,b);
    }
    frac operator *(const frac&rhs)
    {
        __int128 a,b;
        b=q*rhs.q;
        a=p*rhs.p;
        if(b==0) return frac(0,1);
        __int128 g=__gcd(a,b);
        a/=g;
        b/=g;
        return frac(a,b);
    }
    frac operator /(const frac&rhs)
    {
        __int128 a,b;
        b=q*rhs.p;
        a=p*rhs.q;
        if(b==0) return frac(0,1);
        __int128 g=__gcd(a,b);
        a/=g;
        b/=g;
        return frac(a,b);
    }
    bool operator <(const frac&rhs)const
    {
        return p*rhs.q<rhs.p*q;
    }
    bool operator >(const frac&rhs)const
    {
        return p*rhs.q>rhs.p*q;
    }
    bool operator ==(const frac&rhs)const
    {
        return !(p*rhs.q<rhs.p*q)&&!(p*rhs.q>rhs.p*q);
    }
};

大数类

struct BigIntTiny {
    int sign;
    std::vector<int> v;

    BigIntTiny() : sign(1) {}
    BigIntTiny(const std::string &s) { *this = s; }
    BigIntTiny(int v) {
        char buf[21];
        sprintf(buf, "%d", v);
        *this = buf;
    }
    void zip(int unzip) {
        if (unzip == 0) {
            for (int i = 0; i < (int)v.size(); i++)
                v[i] = get_pos(i * 4) + get_pos(i * 4 + 1) * 10 + get_pos(i * 4 + 2) * 100 + get_pos(i * 4 + 3) * 1000;
        } else
            for (int i = (v.resize(v.size() * 4), (int)v.size() - 1), a; i >= 0; i--)
                a = (i % 4 >= 2) ? v[i / 4] / 100 : v[i / 4] % 100, v[i] = (i & 1) ? a / 10 : a % 10;
        setsign(1, 1);
    }
    int get_pos(unsigned pos) const { return pos >= v.size() ? 0 : v[pos]; }
    BigIntTiny &setsign(int newsign, int rev) {
        for (int i = (int)v.size() - 1; i > 0 && v[i] == 0; i--)
            v.erase(v.begin() + i);
        sign = (v.size() == 0 || (v.size() == 1 && v[0] == 0)) ? 1 : (rev ? newsign * sign : newsign);
        return *this;
    }
    std::string to_str() const {
        BigIntTiny b = *this;
        std::string s;
        for (int i = (b.zip(1), 0); i < (int)b.v.size(); ++i)
            s += char(*(b.v.rbegin() + i) + '0');
        return (sign < 0 ? "-" : "") + (s.empty() ? std::string("0") : s);
    }
    bool absless(const BigIntTiny &b) const {
        if (v.size() != b.v.size()) return v.size() < b.v.size();
        for (int i = (int)v.size() - 1; i >= 0; i--)
            if (v[i] != b.v[i]) return v[i] < b.v[i];
        return false;
    }
    BigIntTiny operator-() const {
        BigIntTiny c = *this;
        c.sign = (v.size() > 1 || v[0]) ? -c.sign : 1;
        return c;
    }
    BigIntTiny &operator=(const std::string &s) {
        if (s[0] == '-')
            *this = s.substr(1);
        else {
            for (int i = (v.clear(), 0); i < (int)s.size(); ++i)
                v.push_back(*(s.rbegin() + i) - '0');
            zip(0);
        }
        return setsign(s[0] == '-' ? -1 : 1, sign = 1);
    }
    bool operator<(const BigIntTiny &b) const {
        return sign != b.sign ? sign < b.sign : (sign == 1 ? absless(b) : b.absless(*this));
    }
    bool operator==(const BigIntTiny &b) const { return v == b.v && sign == b.sign; }
    BigIntTiny &operator+=(const BigIntTiny &b) {
        if (sign != b.sign) return *this = (*this) - -b;
        v.resize(std::max(v.size(), b.v.size()) + 1);
        for (int i = 0, carry = 0; i < (int)b.v.size() || carry; i++) {
            carry += v[i] + b.get_pos(i);
            v[i] = carry % 10000, carry /= 10000;
        }
        return setsign(sign, 0);
    }
    BigIntTiny operator+(const BigIntTiny &b) const {
        BigIntTiny c = *this;
        return c += b;
    }
    void add_mul(const BigIntTiny &b, int mul) {
        v.resize(std::max(v.size(), b.v.size()) + 2);
        for (int i = 0, carry = 0; i < (int)b.v.size() || carry; i++) {
            carry += v[i] + b.get_pos(i) * mul;
            v[i] = carry % 10000, carry /= 10000;
        }
    }
    BigIntTiny operator-(const BigIntTiny &b) const {
        if (sign != b.sign) return (*this) + -b;
        if (absless(b)) return -(b - *this);
        BigIntTiny c;
        for (int i = 0, borrow = 0; i < (int)v.size(); i++) {
            borrow += v[i] - b.get_pos(i);
            c.v.push_back(borrow);
            c.v.back() -= 10000 * (borrow >>= 31);
        }
        return c.setsign(sign, 0);
    }
    BigIntTiny operator*(const BigIntTiny &b) const {
        if (b < *this) return b * *this;
        BigIntTiny c, d = b;
        for (int i = 0; i < (int)v.size(); i++, d.v.insert(d.v.begin(), 0))
            c.add_mul(d, v[i]);
        return c.setsign(sign * b.sign, 0);
    }
    BigIntTiny operator/(const BigIntTiny &b) const {
        BigIntTiny c, d;
        d.v.resize(v.size());
        double db = 1.0 / (b.v.back() + (b.get_pos((unsigned)b.v.size() - 2) / 1e4) +
                           (b.get_pos((unsigned)b.v.size() - 3) + 1) / 1e8);
        for (int i = (int)v.size() - 1; i >= 0; i--) {
            c.v.insert(c.v.begin(), v[i]);
            int m = (int)((c.get_pos((int)b.v.size()) * 10000 + c.get_pos((int)b.v.size() - 1)) * db);
            c = c - b * m, d.v[i] += m;
            while (!(c < b))
                c = c - b, d.v[i] += 1;
        }
        return d.setsign(sign * b.sign, 0);
    }
    BigIntTiny operator%(const BigIntTiny &b) const { return *this - *this / b * b; }
    bool operator>(const BigIntTiny &b) const { return b < *this; }
    bool operator<=(const BigIntTiny &b) const { return !(b < *this); }
    bool operator>=(const BigIntTiny &b) const { return !(*this < b); }
    bool operator!=(const BigIntTiny &b) const { return !(*this == b); }
};
posted @ 2021-07-27 09:43  null4785  阅读(66)  评论(0)    收藏  举报