4191 字
21 分钟
算法竞赛模板
2026-02-09
无标签

这里记录了我经常使用的算法竞赛的板子。

在 C++17 以及以上的高版本 C++ 中,模板类拥有自动类型推断。比如下文中的 ST<T> ,只要你传入了 vector<long long>& aT 就等于 long long,无需手动指定。

并查集#

struct DSU {
int tot;
vector<int> pa, size;
DSU(int n) : pa(n+1), size(n+1, 1), tot(n) {
iota(pa.begin(),pa.end(),0);
}
int find(int x){
while (x!=pa[x]){
x=pa[x]=pa[pa[x]];
}
return x;
}
int operator[](int x) {return find(x);}
void unite(int x, int y) {
x=find(x),y=find(y);
if (x==y) return;
tot--;
if (size[x]<size[y]) swap(x,y);
pa[y]=x;
size[x]+=size[y];
}
};

ST 表#

template<typename T=int, class Func = std::function<T(T, T)>>
struct ST {
int n;
vector<vector<T>> st;
vector<int> lg;
Func op;
ST(vector<T>& a, Func _op=[](T x, T y){ return max(x,y); }): n(a.size()-1), lg(a.size()), op(_op){
lg[0]=lg[1]=0;
for (int i=2;i<=n;i++) lg[i]=lg[i>>1]+1;
st.resize(lg[n]+1);
for (int i=0;i<=lg[n];i++) st[i].resize(a.size());
for (int i=1;i<=n;i++) st[0][i]=a[i];
for (int i=1;i<=lg[n];i++){
for (int j=1;j+(1<<i)-1<=n;j++){
st[i][j]=op(st[i-1][j],st[i-1][j+(1<<(i-1))]);
}
}
}
T query(int l,int r){
int p=lg[r-l+1];
return op(st[p][l],st[p][r-(1<<p)+1]);
}
T operator()(int l,int r){
return query(l,r);
}
};

树状数组#

template<typename T=int>
struct fenwick {
int n;
vector<T> t;
fenwick(int _n): n(_n), t(_n+1){}
fenwick(vector<T>& a): n(a.size()-1), t(a.size()){
for (int i=1;i<=n;i++){
t[i]+=a[i];
if (i+(i&(-i))<=n){
t[i+(i&(-i))]+=t[i];
}
}
}
T query(int p){
T res=T{};
while(p){
res+=t[p];
p-=(p&(-p));
}
return res;
}
T operator[](int p){
return query(p);
}
T operator()(int l,int r){
if (l>r) swap(l,r);
return query(r)-query(l-1);
}
void add(int p,T x){
while(p<=n){
t[p]+=x;
p+=(p&(-p));
}
}
};

矩阵 + 快速幂#

template <typename T = long long, int p = 1000000007>
struct matrix {
int n, m;
std::vector<std::vector<T>> a;
matrix(int _n = 0, int _m = 0, T x = T{}) : n(_n), m(_m), a(_n, std::vector<T>(_m, 0)) {
for (int i = 0; i < std::min(n, m); ++i) a[i][i] = x;
}
std::vector<T>& operator[](int i) { return a[i]; }
const std::vector<T>& operator[](int i) const { return a[i]; }
matrix operator*(const matrix& b) const {
matrix ret(n, b.m);
for (int i = 0; i < n; ++i) {
for (int k = 0; k < m; ++k) {
if (!a[i][k]) continue;
long long val = a[i][k];
for (int j = 0; j < b.m; ++j) {
ret[i][j] = (ret[i][j] + val * b.a[k][j]) % p;
}
}
}
return ret;
}
matrix pow(long long b) const {
matrix base = *this;
matrix ret(n, n, T{1});
while (b) {
if (b & 1LL) ret = ret * base;
base = base * base;
b >>= 1LL;
}
return ret;
}
};

Modint#

template<typename T = long long, int mod = 998244353>
struct Mint {
T v;
Mint(T _v = T{}) {
v = _v % mod;
if (v < 0) v += mod;
}
explicit operator int() const { return (int)v; }
explicit operator long long() const { return (long long)v; }
Mint operator+(const Mint &o) const { return Mint(v + o.v); }
Mint operator-(const Mint &o) const { return Mint(v - o.v); }
Mint operator*(const Mint &o) const { return Mint(v * o.v % mod); }
Mint pow(long long e) const {
Mint res(1), base(v);
while (e > 0) {
if (e & 1) res = res * base;
base = base * base;
e >>= 1;
}
return res;
}
Mint inv() const { return pow(mod - 2); }
Mint operator/(const Mint &o) const { return *this * o.inv(); }
Mint& operator+=(const Mint &o) { v += o.v; if (v >= mod) v -= mod; return *this; }
Mint& operator-=(const Mint &o) { v -= o.v; if (v < 0) v += mod; return *this; }
Mint& operator*=(const Mint &o) { v = (v * o.v) % mod; return *this; }
Mint& operator/=(const Mint &o) { return *this *= o.inv(); }
bool operator==(const Mint &o) const { return v == o.v; }
bool operator!=(const Mint &o) const { return v != o.v; }
friend istream& operator>>(istream &is, Mint &m) {
long long x; is >> x;
m = Mint(x);
return is;
}
friend ostream& operator<<(ostream &os, const Mint &m) {
return os << m.v;
}
};
using Z=Mint<long long,998244353>;

区间加线段树#

template <typename T=int>
struct segtree {
vector<T> tree, lazy;
int n;
void push(int cl, int cr, int p) {
int cm = cl + (cr - cl) / 2;
if (cl != cr && lazy[p]) {
lazy[p * 2] += lazy[p];
lazy[p * 2 + 1] += lazy[p];
tree[p * 2] += lazy[p] * (cm - cl + 1);
tree[p * 2 + 1] += lazy[p] * (cr - cm);
lazy[p] = 0;
}
}
T query(int l, int r, int cl, int cr, int p) {
if (l <= cl && cr <= r) return tree[p];
int m = cl + (cr - cl) / 2;
T sum = T{};
push(cl, cr, p);
if (l <= m) sum += query(l, r, cl, m, p * 2);
if (r > m) sum += query(l, r, m + 1, cr, p * 2 + 1);
return sum;
}
void add(int l, int r, T val, int cl, int cr, int p) {
if (l <= cl && cr <= r) {
lazy[p] += val;
tree[p] += (cr - cl + 1) * val;
return;
}
int m = cl + (cr - cl) / 2;
push(cl, cr, p);
if (l <= m) add(l, r, val, cl, m, p * 2);
if (r > m) add(l, r, val, m + 1, cr, p * 2 + 1);
tree[p] = tree[p * 2] + tree[p * 2 + 1];
}
void build(int s, int t, int p, vector<T> &arr) {
if (s == t) {
tree[p] = arr[s];
return;
}
int m = s + (t - s) / 2;
build(s, m, p * 2, arr);
build(m + 1, t, p * 2 + 1, arr);
tree[p] = tree[p * 2] + tree[p * 2 + 1];
}
void build(int s, int t, int p, T init) {
if (s == t) {
tree[p] = init;
return;
}
int m = s + (t - s) / 2;
build(s, m, p * 2, init);
build(m + 1, t, p * 2 + 1, init);
tree[p] = tree[p * 2] + tree[p * 2 + 1];
}
segtree(vector<T> &arr): n(arr.size()), tree(arr.size()<<2), lazy(arr.size()<<2) {
build(0, n-1, 1, arr);
}
segtree(int _n,T init): n(_n), tree(_n<<2), lazy(_n<<2) {
build(0, n-1, 1, init);
}
T query(int l, int r) { return query(l, r, 0, n-1, 1); }
T operator()(int l,int r){ return query(l,r);}
void add(int l, int r, T val) { add(l, r, val, 0, n-1, 1); }
};

区间推平线段树#

template <typename T=int>
struct segtree {
vector<T> tree, lazy;
vector<bool> if_lazy;
int n;
void push(int cl, int cr, int p) {
int cm = cl + (cr - cl) / 2;
if (cl != cr && if_lazy[p]) {
lazy[p * 2] = lazy[p],if_lazy[p*2] = 1;
lazy[p * 2 + 1] = lazy[p],if_lazy[p*2+1] = 1;
tree[p * 2] = lazy[p] * (cm - cl + 1);
tree[p * 2 + 1] = lazy[p] * (cr - cm);
lazy[p] = 0;
if_lazy[p] = 0;
}
}
T query(int l, int r, int cl, int cr, int p) {
if (l <= cl && cr <= r) return tree[p];
int m = cl + (cr - cl) / 2;
T sum = T{};
push(cl, cr, p);
if (l <= m) sum += query(l, r, cl, m, p * 2);
if (r > m) sum += query(l, r, m + 1, cr, p * 2 + 1);
return sum;
}
void modify(int l, int r, T val, int cl, int cr, int p) {
if (l <= cl && cr <= r) {
lazy[p] = val;
if_lazy[p] = 1;
tree[p] = (cr - cl + 1) * val;
return;
}
int m = cl + (cr - cl) / 2;
push(cl, cr, p);
if (l <= m) modify(l, r, val, cl, m, p * 2);
if (r > m) modify(l, r, val, m + 1, cr, p * 2 + 1);
tree[p] = tree[p * 2] + tree[p * 2 + 1];
}
void build(int s, int t, int p, vector<T> &arr) {
if (s == t) {
tree[p] = arr[s];
return;
}
int m = s + (t - s) / 2;
build(s, m, p * 2, arr);
build(m + 1, t, p * 2 + 1, arr);
tree[p] = tree[p * 2] + tree[p * 2 + 1];
}
void build(int s, int t, int p, T init) {
if (s == t) {
tree[p] = init;
return;
}
int m = s + (t - s) / 2;
build(s, m, p * 2, init);
build(m + 1, t, p * 2 + 1, init);
tree[p] = tree[p * 2] + tree[p * 2 + 1];
}
segtree(vector<T> &arr): n(arr.size()), tree(arr.size()<<2), lazy(arr.size()<<2), if_lazy((arr.size()<<2),0) {
build(0, n-1, 1, arr);
}
segtree(int _n,T init): n(_n), tree(_n<<2), lazy(_n<<2), if_lazy((_n<<2),0) {
build(0, n-1, 1, init);
}
T query(int l, int r) { return query(l, r, 0, n-1, 1); }
T operator()(int l,int r){ return query(l,r);}
void modify(int l, int r, T val) { modify(l, r, val, 0, n-1, 1); }
};

区间加 + 推平线段树#

template <typename T=int>
struct segtree {
vector<T> tree, lazy, setv;
vector<char> has;
int n;
void push(int cl, int cr, int p) {
if (cl == cr) {
if (has[p]) { has[p] = 0; lazy[p] = T{}; }
return;
}
if (has[p]) {
has[p * 2] = 1; has[p * 2 + 1] = 1;
setv[p * 2] = setv[p]; setv[p * 2 + 1] = setv[p];
lazy[p * 2] = T{}; lazy[p * 2 + 1] = T{};
tree[p * 2] = setv[p];
tree[p * 2 + 1] = setv[p];
has[p] = 0;
}
if (lazy[p] != T{}) {
if (has[p * 2]) setv[p * 2] += lazy[p]; else lazy[p * 2] += lazy[p];
if (has[p * 2 + 1]) setv[p * 2 + 1] += lazy[p]; else lazy[p * 2 + 1] += lazy[p];
tree[p * 2] += lazy[p];
tree[p * 2 + 1] += lazy[p];
lazy[p] = T{};
}
}
T query(int l, int r, int cl, int cr, int p) {
if (l <= cl && cr <= r) return tree[p];
int m = cl + (cr - cl) / 2;
T sum = T{};
push(cl, cr, p);
if (l <= m) sum = max(sum, query(l, r, cl, m, p * 2));
if (r > m) sum = max(sum, query(l, r, m + 1, cr, p * 2 + 1));
return sum;
}
void add(int l, int r, T val, int cl, int cr, int p) {
if (l <= cl && cr <= r) {
if (has[p]) setv[p] += val; else lazy[p] += val;
tree[p] += val;
return;
}
int m = cl + (cr - cl) / 2;
push(cl, cr, p);
if (l <= m) add(l, r, val, cl, m, p * 2);
if (r > m) add(l, r, val, m + 1, cr, p * 2 + 1);
tree[p] = max(tree[p * 2], tree[p * 2 + 1]);
}
void assign(int l, int r, T val, int cl, int cr, int p) {
if (l <= cl && cr <= r) {
has[p] = 1;
setv[p] = val;
lazy[p] = T{};
tree[p] = val;
return;
}
int m = cl + (cr - cl) / 2;
push(cl, cr, p);
if (l <= m) assign(l, r, val, cl, m, p * 2);
if (r > m) assign(l, r, val, m + 1, cr, p * 2 + 1);
tree[p] = max(tree[p * 2], tree[p * 2 + 1]);
}
segtree(int _n): n(_n), tree(_n<<2), lazy(_n<<2), setv(_n<<2), has((_n<<2)) {
}
T query(int l, int r) { return query(l, r, 0, n-1, 1); }
void add(int l, int r, T val) { add(l, r, val, 0, n-1, 1); }
void assign(int l, int r, T val) { assign(l, r, val, 0, n-1, 1); }
};

单点修改线段树#

template <typename T=int>
struct segtree {
vector<T> tree;
int n;
T query(int l, int r, int cl, int cr, int p) {
if (l <= cl && cr <= r) return tree[p];
int m = cl + (cr - cl) / 2;
T sum = T{};
if (l <= m) sum += query(l, r, cl, m, p * 2);
if (r > m) sum += query(l, r, m + 1, cr, p * 2 + 1);
return sum;
}
void add(int idx, T val, int cl, int cr, int p) {
if (cl == cr && cr == idx) {
tree[p] += val;
return;
}
int m = cl + (cr - cl) / 2;
if (idx <= m) add(idx, val, cl, m, p * 2);
if (idx > m) add(idx, val, m + 1, cr, p * 2 + 1);
tree[p] = tree[p * 2] + tree[p * 2 + 1];
}
void modify(int idx, T val, int cl, int cr, int p) {
if (cl == cr && cr == idx) {
tree[p] = val;
return;
}
int m = cl + (cr - cl) / 2;
if (idx <= m) modify(idx, val, cl, m, p * 2);
if (idx > m) modify(idx, val, m + 1, cr, p * 2 + 1);
tree[p] = tree[p * 2] + tree[p * 2 + 1];
}
void build(int s, int t, int p, vector<T> &arr) {
if (s == t) {
tree[p] = arr[s];
return;
}
int m = s + (t - s) / 2;
build(s, m, p * 2, arr);
build(m + 1, t, p * 2 + 1, arr);
tree[p] = tree[p * 2] + tree[p * 2 + 1];
}
void build(int s, int t, int p, T init) {
if (s == t) {
tree[p] = init;
return;
}
int m = s + (t - s) / 2;
build(s, m, p * 2, init);
build(m + 1, t, p * 2 + 1, init);
tree[p] = tree[p * 2] + tree[p * 2 + 1];
}
segtree(vector<T> &arr): n(arr.size()), tree(arr.size()<<2) {
build(0, n-1, 1, arr);
}
segtree(int _n,T init): n(_n), tree(_n<<2) {
build(0, n-1, 1, init);
}
T query(int l, int r) { return query(l, r, 0, n-1, 1); }
T operator()(int l,int r){ return query(l,r);}
void add(int idx, T val) { add(idx, val, 0, n-1, 1); }
void modify(int idx, T val) { modify(idx, val, 0, n-1, 1); }
};

Lucas 定理#

template<typename T=long long>
struct lucas
{
vector<T>fa,inv;
T p;
lucas(T _p): p(_p), fa(_p), inv(_p){
fa[0]=inv[0]=1;
for (T i=1;i<p;i++){
fa[i]=fa[i-1]*i%p;
inv[i]=qpow(fa[i],p-2);
}
}
T qpow(T a,T b){
T res=1;
while(b){
if (b&1) res=res*a%p;
a=a*a%p;
b>>=1;
}
return res;
}
T c(T a,T b){
if (b>a) return 0;
return fa[a]*inv[a-b]%p*inv[b]%p;
}
T get(T a,T b){
if (not b) return 1;
return get(a/p,b/p)*c(a%p,b%p)%p;
}
T operator()(T a,T b){ return get(a,b); }
};

Manacher#

struct Manacher {
vector<int>p;
int n;
Manacher(string &_s): n(_s.size()*2+2), p(_s.size()*2+2,1) {
string s="$|";
s.reserve(n);
for (auto&&c:_s){
s+=c;
s+='|';
}
for (int t=1,r=0,mid=0;t<n;t++){
if (t<=r) p[t]=min(p[mid*2-t],r-t+1);
while (p[t]<=t and t+p[t]<n and s[t-p[t]]==s[t+p[t]]) p[t]++;
if (p[t]+t>r) r=p[t]+t-1,mid=t;
}
}
bool query(int l,int r){
// 1-indexed
l=l*2,r=r*2;
int mid=(l+r)/2;
return p[mid]>=(r-mid+1);
}
bool operator()(int l,int r){ return query(l,r); }
int operator[](int i){ return p[i]; }
};

预处理的 KMP#

struct KMP {
vector<vector<int>>nxt;
int n,st,ed;
KMP(string &p,int _st='a',int _ed='z'): n(p.size()), st(_st), ed(_ed), nxt(_ed-_st+1,vector(p.size(),0)) {
int pre=0;
nxt[p[0]-st][0]=1;
for (int i=1;i<n;i++){
for (int j=st;j<=ed;j++){
if (j==p[i])
nxt[j-st][i]=i+1;
else
nxt[j-st][i]=nxt[j-st][pre];
}
pre=nxt[p[i]-st][pre];
}
}
int find_first(string &s){
int cur=0;
for (int i=0;i<s.length();i++){
cur=nxt[s[i]-st][cur];
if (cur==n)
return i-n+1;
}
return -1;
}
int find_largest(string &s){
int cur=0,ret=0;
for (int i=0;i<s.length();i++){
cur=nxt[s[i]-st][cur];
if (cur==n)
return n;
if (cur>ret)
ret=cur;
}
return ret;
}
};

Z 函数 / 扩展 KMP#

struct exKMP {
vector<int>z;
int n;
exKMP(string &p): n(p.size()), z(p.size()) {
int l=0;
for (int i=1;i<n;i++){
if (l+z[l]>i) z[i]=min(z[i-l],l+z[l]-i);
while (i+z[i]<n and p[z[i]]==p[i+z[i]]) z[i]++;
if (i+z[i]>l+z[l]) l=i;
}
}
int query(int i){ return (i==0?n:z[i]); }
int operator[](int i){ return query(i); }
};

MillerRabin 快速质数判定#

template<typename T=__int128>
struct MillerRabin{
vector<T> p{2,3,5,7,11,13,17,19,23,29,31,37};
MillerRabin (){}
T qpow(T a,T b,T p){
T res=1;
while(b){
if (b&1) res=res*a%p;
a=a*a%p;
b>>=1;
}
return res;
}
bool check(T x){
if (x<=37){
for (auto&&i:p) if (i==x) return 1;
return 0;
}
T u=x-1,t=0;
while (not (u&1))
(u>>=1),t++;
for (auto&&i:p){
T v=qpow(i,u,x);
if (v==1) continue;
T s=0;
for (;s<t;s++){
if (v==x-1) break;
v=(v*v)%x;
}
if (s==t) return 0;
}
return 1;
}
bool operator()(T x){ return check(x); }
};

NTT 快速数论变换#

template<int mod, int root, typename T = long long>
class NTTProc {
private:
T qpow(T base, T exp) const {
T res = 1;
base %= mod;
while (exp > 0) {
if (exp % 2 == 1) res = (res * base) % mod;
base = (base * base) % mod;
exp /= 2;
}
return res;
}
T qinv(T x) const {
return qpow(x, mod - 2);
}
inline static const T inv_root = NTTProc<mod, root, T>().qinv((T)root);
void trans(vector<T>& a, bool invert) {
int n = a.size();
for (int i = 1, j = 0; i < n; i++) {
int bit = n >> 1;
for (; j & bit; bit >>= 1) {
j ^= bit;
}
j ^= bit;
if (i < j) {
swap(a[i], a[j]);
}
}
for (int len = 2; len <= n; len <<= 1) {
T wlen = qpow(invert ? inv_root : root, (mod - 1) / len);
for (int i = 0; i < n; i += len) {
T w = 1;
for (int j = 0; j < len / 2; j++) {
T u = a[i + j];
T v = (a[i + j + len / 2] * w) % mod;
a[i + j] = (u + v) % mod;
a[i + j + len / 2] = (u - v + mod) % mod;
w = (w * wlen) % mod;
}
}
}
if (invert) {
T n_inv = qinv(n);
for (T& x : a) {
x = (x * n_inv) % mod;
}
}
}
public:
NTTProc() = default;
vector<T> mul(vector<T>& a, vector<T>& b) {
if (a.empty() || b.empty()) return {};
int n = a.size() + b.size() - 1;
int mx = 1;
while (mx < n) {
mx <<= 1;
}
a.resize(mx);
b.resize(mx);
trans(a, false);
trans(b, false);
vector<T> c(mx);
for (int i = 0; i < mx; i++) {
c[i] = (a[i] * b[i]) % mod;
}
trans(c, true);
c.resize(n);
return c;
}
vector<T> operator()(vector<T>& a,vector<T>& b) {
return mul(a, b);
}
};
NTTProc<998244353,3> ntt;

FFT 快速傅里叶变换#

template<typename T = double>
class complex {
public:
using value_type = T;
T re, im;
constexpr complex(T real = T(), T imag = T()) : re(real), im(imag) {}
constexpr complex operator+(const complex& o) const { return complex(re + o.re, im + o.im); }
constexpr complex operator-(const complex& o) const { return complex(re - o.re, im - o.im); }
constexpr complex operator*(const complex& o) const { return complex(re * o.re - im * o.im, re * o.im + im * o.re); }
constexpr complex& operator+=(const complex& o) { re += o.re; im += o.im; return *this; }
constexpr complex& operator-=(const complex& o) { re -= o.re; im -= o.im; return *this; }
constexpr complex& operator*=(const complex& o) { T nr = re * o.re - im * o.im; im = re * o.im + im * o.re; re = nr; return *this; }
constexpr complex operator*(T s) const { return complex(re * s, im * s); }
constexpr complex& operator*=(T s) { re *= s; im *= s; return *this; }
friend constexpr complex operator*(T s, const complex& z) { return z * s; }
static complex unit(T theta) { return complex(std::cos(theta), std::sin(theta)); }
};
template <typename C = ::complex<>, typename T = long long>
class FFTProc {
private:
void trans(vector<C>& a, bool invert) const {
int n = static_cast<int>(a.size());
for (int i = 1, j = 0; i < n; ++i) {
int bit = n >> 1;
for (; j & bit; bit >>= 1) j ^= bit;
j ^= bit;
if (i < j) swap(a[i], a[j]);
}
const double PI = std::acos(-1.0);
for (int len = 2; len <= n; len <<= 1) {
double ang = 2 * PI / len * (invert ? -1.0 : 1.0);
C wlen = C::unit(static_cast<typename C::value_type>(ang));
for (int i = 0; i < n; i += len) {
C w(static_cast<typename C::value_type>(1), static_cast<typename C::value_type>(0));
for (int j = 0; j < (len >> 1); ++j) {
C u = a[i + j];
C v = a[i + j + (len >> 1)] * w;
a[i + j] = u + v;
a[i + j + (len >> 1)] = u - v;
w *= wlen;
}
}
}
if (invert) {
auto inv_n = static_cast<typename C::value_type>(1.0 / n);
for (auto& x : a) x *= inv_n;
}
}
public:
FFTProc() = default;
vector<T> mul(const vector<T>& a, const vector<T>& b) const {
if (a.empty() || b.empty()) return {};
int n = static_cast<int>(a.size() + b.size() - 1);
int mx = 1;
while (mx < n) mx <<= 1;
vector<C> fa(mx), fb(mx);
for (size_t i = 0; i < a.size(); ++i) fa[i] = C(static_cast<typename C::value_type>(a[i]), static_cast<typename C::value_type>(0));
for (size_t i = 0; i < b.size(); ++i) fb[i] = C(static_cast<typename C::value_type>(b[i]), static_cast<typename C::value_type>(0));
trans(fa, false);
trans(fb, false);
for (int i = 0; i < mx; ++i) fa[i] *= fb[i];
trans(fa, true);
vector<T> c(n);
for (int i = 0; i < n; ++i) {
double val = static_cast<double>(fa[i].re);
c[i] = static_cast<T>(std::llround(val));
}
return c;
}
vector<T> operator()(const vector<T>& a, const vector<T>& b) const { return mul(a, b); }
};
FFTProc<> fft;

线性基#

using u64=uint64_t;
template<int MX=31>
struct LinearBasis {
array<u64,MX> b{},msk{};
vector<int> idx;
void insert(u64 x,int p) {
u64 cur=0,nxt=1ull<<idx.size();
for (int i=MX-1;i>=0;--i) {
if (((x>>i)&1)==0) continue;
if (not b[i]){
b[i]=x;
msk[i]=cur|nxt;
idx.push_back(p);
return;
}
x^=b[i];
cur^=msk[i];
}
}
array<u64,2> max(){
u64 ans=0,res=0;
for (int i=MX-1;i>=0;--i) {
if (not b[i]) continue;
u64 nxt=ans^b[i];
if (nxt>ans){
ans=nxt;
res^=msk[i];
}
}
return {ans,res};
}
array<u64,2> find(int tar){
u64 x=tar,res=0;
for (int i=MX-1;i>=0;--i) {
if (((x>>i)&1)==0) continue;
if (not b[i]){
return {0ull,0ull};
}
x^=b[i];
res^=msk[i];
}
return {1ull,res};
}
};

拉格朗日插值定理 / 重心拉格朗日#

template <class T>
struct Lag {
static vector<T> coef(const vector<array<T,2>>& p) {
int n = (int)p.size();
if (n == 0) return {};
if (n == 1) return {p[0][1]};
vector<T> x(n), y(n);
for (int i = 0; i < n; ++i) { x[i] = p[i][0]; y[i] = p[i][1]; }
vector N(1, T(1));
for (int i = 0; i < n; ++i) N = mul(N, x[i]);
vector a(n, T(0));
for (int i = 0; i < n; ++i) {
T d = T(1);
for (int j = 0; j < n; ++j) if (j != i) d *= (x[i] - x[j]);
vector q = div(N, x[i]);
T s = y[i] / d;
for (int k = 0; k < n; ++k) a[k] += q[k] * s;
}
return a;
}
static T eval_eq(const vector<array<T,2>>& p, const T& x) {
int n = (int)p.size();
if (n == 0) return T(0);
if (n == 1) return p[0][1];
T s = p[0][0];
T h = p[1][0] - p[0][0];
for (int i = 0; i < n; ++i) {
if (x == s + T(i) * h) return p[i][1];
}
T t = (x - s) / h;
T w0 = ((n - 1) & 1) ? T(0) - T(1) : T(1);
for (int r = 1; r <= n - 1; ++r) w0 /= T(r);
T num = T(0), den = T(0), wi = w0;
for (int i = 0; i < n; ++i) {
T ti = wi / (t - T(i));
num += ti * p[i][1];
den += ti;
if (i + 1 < n) wi = (T(0) - wi) * T(n - 1 - i) / T(i + 1);
}
return num / den;
}
static vector<T> operator()(const vector<array<T,2>>& p) {
return coef(p);
}
// x 等差时
static vector<T> operator()(const vector<array<T,2>>& p, const T& x) {
return eval_eq(p,x);
}
private:
static vector<T> mul(const vector<T>& a, const T& r) {
vector b(a.size() + 1, T(0));
for (int i = (int)a.size() - 1; i >= 0; --i) b[i + 1] += a[i];
T nr = T(0) - r;
for (int i = 0; i < (int)a.size(); ++i) b[i] += a[i] * nr;
return b;
}
static vector<T> div(const vector<T>& a, const T& r) {
int n = (int)a.size() - 1;
if (n < 0) return {};
vector q(n, T(0));
T cur = a[n];
for (int k = n - 1; k >= 1; --k) {
q[k] = cur;
cur = a[k] + cur * r;
}
if (n >= 1) q[0] = cur;
return q;
}
};
using Z=Mint<long long,998244353>;
Lag<Z> lag={};
// Lag<double> lag={};

平衡树#

#include<bits/extc++.h>
template<typename T=int>
using rbtree=__gnu_pbds::tree<T,__gnu_pbds::null_type,less<T>,__gnu_pbds::rb_tree_tag,__gnu_pbds::tree_order_statistics_node_update>;
/* order_of_key()
* find_by_order() iterator
*/

exgcd#

def exgcd(a,b):
ps,s,pt,t,pr,r=1,0,0,1,a,b
while r:
q=pr//r
pr,r=r,pr-q*r
pt,t=t,pt-q*t
ps,s=s,ps-q*s
return pr,ps,pt
算法竞赛模板
https://zrn.net/posts/cp-templates/
作者
Poi
发布于
2026-02-09
许可协议
CC BY-NC-SA 4.0