constexpr int mod = 998244353;
int q_pow(int a, int b)
{if (!a)return 1ll;int res = 1;while (b){if (b & 1)res = res * a % mod; a = a * a % mod;b >>= 1;}return res;
}int fen(int u, int d)
{return u % mod * q_pow(d % mod, mod - 2) % mod;
}
2.区间第k位为1的个数
int count(int X, int k) // 区间 [0,X] 中第 k 位为 1 的数的个数 / 此位1的个数
{return (X + 1) / (1ll << k + 1) * (1ll << k) + max(0ll, (X + 1) % (1ll << k + 1) - (1ll << k));
}
3. 整除分块
int l = 1, r = 0;while (l <= min(n, k)){r = k / (k / l);r = min(r, n);int ans = k / l * (l + r) * (r - l + 1) / 2;res -= ans;l = r + 1;}
4. 自动模数(简洁版
using i64 = long long;
template <int MOD>
struct MInt
{i64 x;int norm(i64 u) const{u %= MOD;if (u < 0)u += MOD;return u;}MInt(i64 v = 0) : x(norm(v)) {}int val() const { return x; }MInt operator-() const { return MInt(norm(MOD - x)); }MInt inv() const{assert(x != 0);return power(MOD - 2);}MInt &operator*=(const MInt &o){x = norm(x * o.x);return *this;}MInt &operator+=(const MInt &o){x = norm(x + o.x);return *this;}MInt &operator-=(const MInt &o){x = norm(x - o.x);return *this;}MInt &operator/=(const MInt &o){*this *= o.inv();return *this;}friend MInt operator*(const MInt &a, const MInt &b){MInt ans = a;ans *= b;return ans;}friend MInt operator+(const MInt &a, const MInt &b){MInt ans = a;ans += b;return ans;}friend MInt operator-(const MInt &a, const MInt &b){MInt ans = a;ans -= b;return ans;}friend MInt operator/(const MInt &a, const MInt &b){MInt ans = a;ans /= b;return ans;}friend bool operator==(const MInt &a, const MInt &b){return a.val() == b.val();}friend bool operator!=(const MInt &a, const MInt &b){return !(a == b);}friend bool operator<(const MInt &a, const MInt &b){return a.val() < b.val();}friend std::istream &operator>>(std::istream &is, MInt &a){i64 u;is >> u;a = MInt(u);return is;}friend std::ostream &operator<<(std::ostream &os, const MInt &a){os << a.val();return os;}MInt power(i64 b) const{i64 r = 1, t = x;while (b){if (b & 1)r = r * t % MOD;t = t * t % MOD;b /= 2;}return MInt(r);}
};const int mod = 998244353;
using mint = MInt<mod>;struct Fact
{vector<mint> fact, factinv;const int n;Fact(const int &_n) : n(_n), fact(_n + 1, mint(1)), factinv(_n + 1){for (int i = 1; i <= n; ++i)fact[i] = fact[i - 1] * i;factinv[n] = fact[n].inv();for (int i = n; i; --i)factinv[i - 1] = factinv[i] * i;}mint C(const int &n, const int &k){if (n < 0 || k < 0 || n < k)return 0;return fact[n] * factinv[k] * factinv[n - k];}mint A(const int &n, const int &k){if (n < 0 || k < 0 || n < k)return 0;return fact[n] * factinv[n - k];}
}; // Fact fact(n);
// mint(2).power(10)
5. 区间在bit位1的个数
auto calc = [&](int N, int bit) // 1~n中在bit位1的个数{++N;return (N >> (bit + 1) << bit) + min(1ll << bit, N % (1ll << (bit + 1)));};auto cal = [&](int l, int r, int bit) // l~r中在bit位1的个数{return l == 1 ? calc(r, bit) : calc(r, bit) - calc(l - 1, bit);};
6. 二进制数位DP(TLE有更优方案
int ok(int x) // [0,x]二进制中1的个数为m 的数字个数
{vector<int> num(1);int len = 0;int t = x;while (t){num.push_back(t & 1);t >>= 1;len++;}vector<vector<vector<int>>> f(len + 1, vector<vector<int>>(len + 1, vector<int>(2, -1)));auto dfs = [&](auto &&self, int u, int pre, int lim) -> int{if (!u){return pre == m; // 满足条件为1}// 可剪枝// 剪枝:pre超过m 或 剩余位数全选1也无法达到mif (pre > m)return 0;if (pre + u < m)return 0;if (~f[u][pre][lim])return f[u][pre][lim];int maxk = lim ? num[u] : 1;int res = 0;for (int i = 0; i <= maxk; i++){res += self(self, u - 1, pre + i, lim && i == maxk);}return f[u][pre][lim] = res;};int res = dfs(dfs, len, 0, 1);// cout << res << '\n';return res;
}
7. 数位DP
int digitDP(string s, int d) // [0,x]数位和为d的倍数的个数
{vector<int> num{0};reverse(s.begin(), s.end());for (auto v : s)num.push_back(v - '0');int len = num.size() - 1;vector<vector<vector<int>>> f(len + 1, vector<vector<int>>(d, vector<int>(2, -1))); // sizeauto dfs = [&](auto &&self, int u, int pre, int lim) -> int{if (!u){return pre == 0; // 满足条件为1}// 可剪枝if (~f[u][pre][lim])return f[u][pre][lim];int maxk = lim ? num[u] : 9;int res = 0;for (int i = 0; i <= maxk; i++){res += self(self, u - 1, (pre + i) % d, lim && i == maxk);res %= mod;}return f[u][pre][lim] = res;};return dfs(dfs, len, 0, 1);
}
8. 莫比乌斯函数预处理
auto getmu = [&](int n){int tot = 0;vector<int> mu(n + 1), flg(n + 1), p(n + 1);mu[1] = 1;for (int i = 2; i <= n; ++i){if (!flg[i])p[++tot] = i, mu[i] = -1;for (int j = 1; j <= tot && i * p[j] <= n; ++j){flg[i * p[j]] = 1;if (i % p[j] == 0){mu[i * p[j]] = 0;break;}mu[i * p[j]] = -mu[i];}}return mu;};
9. debug(新版
namespace DBG
{template <class T>void _dbg(const char *f, T t) { cerr << f << '=' << t << '\n'; }template <class A, class... B>void _dbg(const char *f, A a, B... b){while (*f != ',')cerr << *f++;cerr << '=' << a << ",";_dbg(f + 1, b...);}template <typename Container>void _print(const char *f, const Container &v){cerr << f << " = [ ";for (const auto &x : v)cerr << x << ", ";cerr << "]\n";}
#define bug(...) _dbg(#__VA_ARGS__, __VA_ARGS__)
#define bugv(container) _print(#container, container)
}
using namespace DBG;
10.带权并查集
// 带权并查集
struct DSU
{vector<int> p, vs, es; // 集合数 点数 边数 (图:对一个连通块而言)vector<int> xor_val; // 维护每个点与父节点之间的路径异或和DSU(int n1) // p[x]不一定为根节点 find(x)一定是根节点{int n = n1 + 10;p.assign(n, 0);vs.assign(n, 0);es.assign(n, 0);xor_val.assign(n, 0);for (int i = 1; i <= n1; i++)p[i] = i, vs[i] = 1, es[i] = 0;}int find(int x) // 找到根节点{if (p[x] == x)return x;int px = find(p[x]);xor_val[x] ^= xor_val[p[x]];return p[x] = px;}bool same(int a, int b) { return find(a) == find(b); }int merge(int a, int b, int val = 0) // 合并集合 返回:-1 该边不会形成环 >=0 简单环的边权异或和{int pa = find(a);int pb = find(b);if (pa == pb) // pa pb 均为根节点 p[pa]==pa{es[pa]++; // 1个集合 边+1return xor_val[a] ^ xor_val[b] ^ val;}p[pb] = pa; // 改变b的根节点xor_val[pb] = xor_val[a] ^ xor_val[b] ^ val;vs[pa] += vs[pb]; // 将b合并进aes[pa] += es[pb] + 1; // 2个集合return -1;}int size(int a) { return vs[find(a)]; } // 集合内的元素的个数
}; // DSU dsu(n);
11.倍增lca
const int N = 2e5 + 10;
int n, m, s, a, b;
vector<int> e[N];
int dep[N];
int fa[N][20];
void dfs(int u, int father)
{dep[u] = dep[father] + 1; // 设置当前节点深度fa[u][0] = father; // 直接父节点// 预处理二进制提升表for (int i = 1; i <= 19; i++)fa[u][i] = fa[fa[u][i - 1]][i - 1];// 递归处理子节点for (int v : e[u])if (v != father)dfs(v, u);
}
int lca(int u, int v)
{// 确保u是较深的节点if (dep[u] < dep[v])swap(u, v);// 将u提升到与v同一深度for (int i = 19; i >= 0; i--)if (dep[fa[u][i]] >= dep[v])u = fa[u][i];if (u == v)return v; // 如果已经是同一节点// 同时提升u和v直到它们的父节点相同for (int i = 19; i >= 0; i--)if (fa[u][i] != fa[v][i])u = fa[u][i], v = fa[v][i];return fa[u][0]; // 返回LCA
}
12.线段树0
#define ls (u << 1)
#define rs (u << 1 | 1)template <class info>
struct Tree
{int n;vector<int> a;vector<info> tr;void pushdown(int u){upd(ls, tr[u].tag);upd(rs, tr[u].tag);tr[u].tag = 0;}Tree(int _n, vector<int> &_a){n = _n;a.assign(n + 1, 0);for (int i = 1; i <= n; i++)a[i] = _a[i];tr.assign((n + 5) << 2, info{});build(1, 1, n);}void build(int u, int l, int r){tr[u].l = l, tr[u].r = r;if (l == r){bui(u, r);return;}int mid = l + r >> 1;build(ls, l, mid);build(rs, mid + 1, r);pushup(u);}void update(int u, int l, int r, int val){if (l <= tr[u].l && tr[u].r <= r){upd(u, val);return;}if (tr[u].tag)pushdown(u);int mid = tr[u].l + tr[u].r >> 1;if (l <= mid)update(ls, l, r, val);if (r > mid)update(rs, l, r, val);pushup(u);}info ask(int u, int l, int r){info res = {};if (tr[u].r < l || tr[u].l > r){return res;}if (l <= tr[u].l && tr[u].r <= r){res = res + tr[u];return res;}if (tr[u].tag)pushdown(u);int mid = tr[u].l + tr[u].r >> 1;if (l <= mid)res = res + ask(ls, l, r);if (r > mid)res = res + ask(rs, l, r);return res;}void pushup(int u){tr[u] = tr[ls] + tr[rs];}info ask(int l, int r) { return ask(1, l, r); }void update(int l, int r, int val = 0) { update(1, l, r, val); }void bui(int u, int inx) // 叶子{tr[u].sum = a[inx];tr[u].mx = tr[u].mn = a[inx];}void upd(int u, int val) // 上对下更新 更新tag对子节点影响 考虑tag累计存储{int L = tr[u].l, R = tr[u].r;tr[u].sum += (R - L + 1) * val;tr[u].mx += val, tr[u].mn += val;tr[u].tag += val;}
};
struct info
{int l, r, sum, mx = -1e18, mn = 1e18, tag; // 属性info operator+(const info &b) const{info res = {};res.l = this->l;res.r = b.r;res.sum = sum + b.sum; // 下对上更新 合并答案res.mx = max(mx, b.mx);res.mn = min(mn, b.mn);return res;}
}; // Tree<info> tr(n, a);
13.线段树1
// long long careful
constexpr int mod = 1e9 + 7;
#define ls (u << 1)
#define rs (u << 1 | 1)template <class Info, class Tag>
struct Tree
{int n;vector<int> a;vector<Info> tr;Tree() {}Tree(int _n, vector<int> &_a){init(_n, _a);}void init(int _n, vector<int> &_a){n = _n;a.assign(n + 1, 0);tr.assign((n + 5) << 2, Info{});for (int i = 1; i <= n; i++)a[i] = _a[i];build(1, 1, n);}void build(int u, int l, int r){tr[u].l = l, tr[u].r = r;if (l == r){bui(u, r);return;}int mid = l + r >> 1;build(ls, l, mid);build(rs, mid + 1, r);pushup(u);}void update(int u, int l, int r, int val, int fg){if (tr[u].r < l || tr[u].l > r)return;if (tr[u].l == tr[u].r) // 单点修改{if (fg == 1){tr[u].sum = tr[u].mx = val;}else{tr[u].sum = tr[u].mx = tr[u].sum % val;}return;}if (fg == 4 && tr[u].mx < val)return;// if (l <= tr[u].l && tr[u].r <= r) //区间修改// {// upd(u, val, fg);// return;// }pushdown(u);int mid = tr[u].l + tr[u].r >> 1;if (l <= mid)update(ls, l, r, val, fg);if (r > mid)update(rs, l, r, val, fg);pushup(u);}Info ask(int u, int l, int r){Info res = {};if (tr[u].r < l || tr[u].l > r)return res;if (l <= tr[u].l && tr[u].r <= r){res = res + tr[u];return res;}pushdown(u);int mid = tr[u].l + tr[u].r >> 1;if (l <= mid)res = res + ask(ls, l, r);if (r > mid)res = res + ask(rs, l, r);return res;}Info ask(int l, int r) { return ask(1, l, r); }void update(int l, int r, int val, int fg) { update(1, l, r, val, fg); }void debug(){cerr << "debug:>\n";for (int i = 1; i <= n; i++)bug(i, Tree::ask(i, i).sum);}void module(int u){tr[u].sum %= mod;tr[u].tag.add %= mod;tr[u].tag.mul %= mod;}void pushup(int u){tr[u] = tr[ls] + tr[rs];// module(u);}void bui(int u, int inx) // 叶子{int val = a[inx];tr[u].sum = val;// tr[u].mxpre = tr[u].mxsuf = tr[u].mxrange = val;// tr[u].sum2 = val * val;tr[u].mx = val;// tr[u].mn = val;}void pushdown(int u){auto &tag = tr[u].tag;// upd(ls, tr[u].tag.ass, 1);// upd(rs, tr[u].tag.ass, 1);// upd(ls, tr[u].tag.mul, 2);// upd(rs, tr[u].tag.mul, 2);// upd(ls, tr[u].tag.add, 3);// upd(rs, tr[u].tag.add, 3);// upd(ls, tag.xor_, 4);// upd(rs, tag.xor_, 4);tag.clear();}void upd(int u, int val, int fg) // 上对下更新 更新tag对子节点影响 考虑tag累计存储{int l = tr[u].l, r = tr[u].r;auto &tag = tr[u].tag;if (fg == 1 && val > -1e9) // ={// tr[u].sum = (r - l + 1) * val;// tr[u].mxpre = tr[u].mxsuf = tr[u].mxrange = (r - l + 1) * val;// tr[u].sum = 1 << val;// tr[u].sum2 = val * val; // 单点// tr[u].mx = val;// tr[u].mn = val;// tag.ass = val;// tag.xor_ = 0;// tag.mul = 1;// tag.add = 0;}else if (fg == 2 && val - 1) // *{// tr[u].sum = tr[u].sum * val;// tr[u].mx *= val;// tr[u].mn *= val;// tag.mul *= val;// tag.add *= val;}else if (fg == 3 && val) // +{// tr[u].sum += (r - l + 1) * val;// tr[u].mx += val;// tr[u].mn += val;// tag.add += val;}else if (fg == 4 && val) // xor{// tr[u].sum = r - l + 1 - tr[u].sum;// // ...// tag.xor_ ^= 1;}// module(u);}
};
struct Tag
{int add = 0;// int mul = 1;// int xor_ = 0;// int ass = -1e12;void clear(){add = 0;// mul = 1;// xor_ = 0;// ass = -1e12;}
};
struct Info
{int l, r, sum; // 属性// int mxpre = -1e12, mxsuf = -1e12, mxrange = -1e12;// int sum2;int mx = -1e9;// int mn = 1e9;Tag tag = {};Info operator+(const Info &b) const{Info res = {};res.l = this->l;res.r = b.r;res.sum = sum + b.sum; // 下对上更新 合并答案// res.sum %= mod;// res.mxpre = max(mxpre, sum + b.mxpre), res.mxsuf = max(b.mxsuf, b.sum + mxsuf);// res.mxrange = max({mxrange, b.mxrange, mxsuf + b.mxpre, res.mxpre, res.mxsuf});// res.sum2 = sum2 + b.sum2;// res.sum2 %= mod;res.mx = max(mx, b.mx);// res.mn = min(mn, b.mn);return res;}
}; // Tree<Info,Tag> tr(n,a);
14.线段树2
// long long careful
constexpr int mod = 1e9 + 7;
#define ls (u << 1)
#define rs (u << 1 | 1)template <class Info, class Tag>
struct Tree
{int n;vector<int> a;vector<Info> tr;Tree() {}Tree(int _n, vector<int> &_a){init(_n, _a);}void init(int _n, vector<int> &_a){n = _n;a.assign(n + 1, 0);tr.assign((n + 5) << 2, Info{});for (int i = 1; i <= n; i++)a[i] = _a[i];build(1, 1, n);}void build(int u, int l, int r){tr[u].l = l, tr[u].r = r;if (l == r){bui(u, r);return;}int mid = l + r >> 1;build(ls, l, mid);build(rs, mid + 1, r);pushup(u);}void update(int u, int l, int r, int val, int fg){if (tr[u].r < l || tr[u].l > r)return;// if (tr[u].l == tr[u].r) // 单点修改// {// tr[u].sum = tr[u].mxpre = tr[u].mxsuf = tr[u].mxrange = val;// return;// }// if (fg == 4 && tr[u].mx < val) // 剪枝// return;if (l <= tr[u].l && tr[u].r <= r) // 区间修改{upd(u, val, fg);return;}pushdown(u);int mid = tr[u].l + tr[u].r >> 1;if (l <= mid)update(ls, l, r, val, fg);if (r > mid)update(rs, l, r, val, fg);pushup(u);}Info ask(int u, int l, int r){Info res = {};if (tr[u].r < l || tr[u].l > r)return res;if (l <= tr[u].l && tr[u].r <= r){res = res + tr[u];return res;}pushdown(u);int mid = tr[u].l + tr[u].r >> 1;if (l <= mid)res = res + ask(ls, l, r);if (r > mid)res = res + ask(rs, l, r);return res;}Info ask(int l, int r) { return ask(1, l, r); }void update(int l, int r, int val, int fg) { update(1, l, r, val, fg); }void debug(){cerr << "debug:>\n";for (int i = 1; i <= n; i++)bug(i, Tree::ask(i, i).mxrange);}void module(int u){tr[u].sum %= mod;tr[u].tag.add %= mod;tr[u].tag.mul %= mod;}void pushup(int u){tr[u] = tr[ls] + tr[rs];// module(u);}void bui(int u, int inx) // 叶子 对属性初始化{int val = a[inx];tr[u].sum = val;// tr[u].mxpre = tr[u].mxsuf = tr[u].mxrange = val;// tr[u].sum2 = val * val;// tr[u].mx = val;// tr[u].mn = val;}void pushdown(int u){auto &tag = tr[u].tag;// upd(ls, tr[u].tag.ass, 1);// upd(rs, tr[u].tag.ass, 1);// upd(ls, tr[u].tag.mul, 2);// upd(rs, tr[u].tag.mul, 2);// upd(ls, tr[u].tag.add, 3);// upd(rs, tr[u].tag.add, 3);// upd(ls, tag.xor_, 4);// upd(rs, tag.xor_, 4);tag.clear();}void upd(int u, int val, int fg) // 上对下更新 对属性计算标记影响并传递标记{int l = tr[u].l, r = tr[u].r;auto &tag = tr[u].tag;if (fg == 1 && val > -1e9) // ={// tr[u].sum = (r - l + 1) * val;// tr[u].mxpre = tr[u].mxsuf = tr[u].mxrange = (r - l + 1) * val;// tr[u].sum = 1 << val;// tr[u].sum2 = val * val; // 单点// tr[u].mx = val;// tr[u].mn = val;// tag.ass = val;// tag.xor_ = 0;// tag.mul = 1;// tag.add = 0;}else if (fg == 2 && val - 1) // *{// tr[u].sum = tr[u].sum * val;// tr[u].mx *= val;// tr[u].mn *= val;// tag.mul *= val;// tag.add *= val;}else if (fg == 3 && val) // +{// tr[u].sum += (r - l + 1) * val;// tr[u].mx += val;// tr[u].mn += val;// tag.add += val;}else if (fg == 4 && val) // xor{// tr[u].sum = r - l + 1 - tr[u].sum;// tag.xor_ ^= 1;}// module(u);}
};
struct Tag // 标记:需要对区间更新的值
{// int add = 0;// int mul = 1;// int xor_ = 0;// int ass = -1e12;void clear(){// add = 0;// mul = 1;// xor_ = 0;// ass = -1e12;}
};
struct Info // 属性:所要维护的值
{int l, r, sum;// int mxpre = -1e12, mxsuf = -1e12, mxrange = -1e12;// int sum2;// int mx = -1e9;// int mn = 1e9;Tag tag = {};Info operator+(const Info &b) const{Info res = {};res.l = this->l;res.r = b.r;res.sum = sum + b.sum; // 下对上更新 合并属性// res.sum %= mod;// res.mxpre = max(mxpre, sum + b.mxpre), res.mxsuf = max(b.mxsuf, b.sum + mxsuf);// res.mxrange = max({mxrange, b.mxrange, mxsuf + b.mxpre, res.mxpre, res.mxsuf});// res.sum2 = sum2 + b.sum2;// res.sum2 %= mod;// res.mx = max(mx, b.mx);// res.mn = min(mn, b.mn);return res;}
}; // Tree<Info,Tag> tr(n,a);