并查集
(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以下
#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;
}
}//考虑异或