算法模板
算法模板
数论
//最大公约数
int gcd(int a, int b) {
if (a < b) return gcd(b, a);
if (a % b == 0) return b;
return gcd(b, a%b);
}
//筛法求素数
#define MX 10000
vector<int> primes;
bool np[MX + 1];
void init (int n = MX){
for (int i = 2; i <= n; i++) {
if (!np[i]) {
primes.push_back(i);
for (int j = i; j <= n / i; j++) // 避免溢出的写法
np[i * j] = true;
}
}
}
//快速幂
long long binpow(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 binpow(long long a, long long b, int mod) {
long long res = 1;
while (b > 0) {
if (b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
//组合数
long long int combi(int n,int m){//求组合数的函数
long long int cnt = 1;
for(int i = 0; i < m; i++){
cnt *= n - i;
cnt /= i + 1;
}
return cnt;
}
//卡特兰数
//应用:在n个元素出栈的可能性次数;二叉树的中序序列已知,求二叉树的种类的个数;n个节点的二叉树有多少种。
/*
公式一
递归公式
h(0)=h(1)=1
h(n)=h(0)∗h(n−1)+h(1)∗h(n−2)+...+h(n−1)∗h(0)(n>=2)
如果我们用这个公式显然我们要使用递归算法,那么数据一大就在时空上很麻烦
*/
long long int catalan(int n) {
if (n <= 1) return 1;
long long int ret = 0;
for (int i = 0; i < n; i++) {
ret += catalan(i) * catalan(n-1-i);
}
return ret;
}
/*
公式二
递推公式
h(n)=h(n−1)∗(4∗n−2)/(n+1)
这个公式应用递推,看上起十分和善
但对大数据呢?
我们注意到大数据的时候h(n)会很大,这时候题目一般会让你对某素数取模(当然你可以打高精度(划掉))
但你在取模过程中难保一个h(n)%mod=0
那么根据公式下面所有的数都会等于0,于是你就愉快的WA了
*/
long long int catalan(int n)
{
long long int f[25]{0};
f[0] = 1;
for (int i = 1; i <= n; i++) f[i] = f[i - 1] * (4 * i - 2) / (i + 1);
return f[n];
}
/*
公式三
组合数公式1
h(n)=C(2n,n)/(n+1)(n=0,1,2,...)
卡特兰数可以与组合数联系起来,得到上面的公式
而组合数就是一个杨辉三角,可以递推得到(这个不属于这道题的讨论范围我假装你们都会(逃))
但我们发现对于大数据你要取模,而对于除法你是没办法用膜的性质的(当然你可以应用逆元(划掉)),所以造成了麻烦
公式四
组合数公式2
h(n)=c(2n,n)−c(2n,n−1)(n=0,1,2,...)
与组合数公式1不同这个是两个组合数的减法
减法是可以用膜的性质的,于是你可以愉快的AC了。
*/
统计
并查集
struct UF{
int n;
int cnt;
vector<int> fa;
vector<int> sz;
UF(int _n) : n(_n), cnt(_n), fa(_n), sz(_n, 1) {
iota(fa.begin(), fa.end(), 0);
}
int find(int x) {
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
bool merge(int x, int y) {
int fx = find(x);
int fy = find(y);
if (fx == fy) return false;
if (sz[fx] < sz[fy]) swap(fx, fy);
fa[fy] = fx;
sz[fx] += sz[fy];
cnt--;
return true;
}
bool connected(int x, int y) {
int fx = find(x);
int fy = find(y);
return (fx == fy);
}
};
树状数组
struct BIT {
vector<long long> tree;
BIT(int n): tree(n+1){}
static constexpr int lowbit(int x) {
return x & (-x);
}
void update(int index, int delta) {
// x是从1开始的下标
for (int i = index; i < tree.size(); i += lowbit(i)) {
tree[i] += delta;
}
}
//查询区间(0,x)的和
long long query(int x) {
long long res = 0;
// 从右到左查询,最小到1,不能等于0
for (int i = x; i > 0; i -= lowbit(i)) {
res += tree[i];
}
return res;
}
// 查询区间[l, r]的和
long long query(int l, int r) {
return query(r+1) - query(l);
}
};
MISC
二分法
版本1
当我们将区间[l, r]划分成[l, mid]和[mid + 1, r]时,其更新操作是r = mid或者l = mid + 1;计算mid时不需要加1。
int bsearch_1(int l, int r)
{
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
return l;
}
版本2
当我们将区间[l, r]划分成[l, mid-1]和[mid, r]时,其更新操作是r = mid - 1或者l = mid;此时为了防止死循环,计算mid时需要加1。
int bsearch_2(int l, int r)
{
while (l < r)
{
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
return l;
}

浙公网安备 33010602011771号