部分常用小功能模板【自用】

gcd最大公因数(__gcd即可)

int gcd(int a, int b) {
	return b == 0 ? a : gcd(b, a % b);
}

快速幂取模

//sum = a^n % mod
ll qpow(ll a,ll n,ll mod) { //快速幂
	ll sum = 1;
	while(n) {
		if(n & 1)
			sum = sum*a%mod;
		n >>= 1;
		a = a*a%mod;
	}
	return sum % mod;
}

二分查找

//按从小到大排序
int ans1 = lower_bound(arr, arr+n, num) - arr;    //返回数组中第一个大于或等于被查数的值 
int ans2 = upper_bound(arr, arr+n, num) - arr;    //返回数组中第一个大于被查数的值 

//按从大到小排序
int ans3 = lower_bound(arr, arr+n, num, greater<int>()) - arr;  //返回数组中第一个小于或等于被查数的值 
int ans4 = upper_bound(arr, arr+n, num, greater<int>()) - arr;  //返回数组中第一个小于被查数的值 

背包

void ZeroOnePack(int cost, int weight) {
	for(int i=nValue;i>=cost;i--) {
		dp[i] = max(dp[i],dp[i-cost]+weight);
	}
}

void CompletePack(int cost, int weight) {
	for(int i=cost;i<=nValue;i++) {
		dp[i] = max(dp[i],dp[i-cost]+weight);
	}
}

void MultiplePack(int cost, int weight, int amount) {
	if(cost * amount >= nValue) {
		CompletePack(cost,weight);
	}
	else {
		int k = 1;
		while(k < amount) {
			ZeroOnePack(k*cost,k*weight);
			amount -= k;
			k <<= 1;
		}
		ZeroOnePack(amount*cost,amount*weight);
	}
}

Miller_Rabin 算法进行素数测试模板

//特点:速度快、可以判断一个小于 2^63 的数是不是素数 
const int S = 8;  //随机算法判定次数一般 8~10 就够了

//计算 ret = (a * b) % c	a,b,c < 2^63
ll mult_mod(ll a, ll b, ll c) {
	a %= c;
	b %= c;
	ll ret = 0;
	ll tmp = a;
	while(b) {
		if(b & 1) {
			ret += tmp;
			if(ret > c) {
				ret -= c;  //直接取模慢很多
			}
		}
		tmp <<= 1;
		if(tmp > c) {
			tmp -= c;
		}
		b>>=1;
	}
	return ret;
}

//计算 ret = (a^n) % mod  快速幂
ll pow_mod(ll a, ll n, ll mod) {
	ll ret = 1;
	ll temp = a % mod;
	while(n) {
		if(n & 1) {
			ret = mult_mod(ret,temp,mod);
		}
		temp = mult_mod(temp,temp,mod);
		n >>= 1;
	}
	return ret;
}

//通过a^(n-1)=1(mod n)来判断 n 是不是素数
//n-1 = x*2^t 中间使用二次判断
//是合数返回true,不一定是合数返回false
bool check(ll a, ll n, ll x, ll t) {
	ll ret = pow_mod(a,x,n);
	ll last = ret;
	for(int i=1; i<=t; i++) {
		ret = mult_mod(ret,ret,n);
		if(ret == 1 && last != 1 &&last != n-1) {
			return true;
		}
		last = ret;
	}
	if(ret != 1) {
		return true;
	} else {
		return false;
	}
}

//Miller_Rabin算法 
//是素数返回true(可能是伪素数) 
//不是素数返回false 
bool Miller_Rabin(ll n) {
	if(n < 2) {
		return false;  //1、0和负数都不是素数 
	}
	if(n == 2) {
		return true;  //2是素数 
	}
	if((n & 1) == 0) {
		return false;  //除了2的偶数都不是素数 
	}
	ll x = n - 1;
	ll t = 0;
	while((x & 1) == 0) {
		x >>= 1;
		t++;
	}
	srand(time(NULL));
	for(int i=0; i<S; i++) {
		ll a = rand() % (n-1) + 1;
		if(check(a,n,x,t)) {
			return false;
		}
	}
	return true;
}

扩展欧几里得算法求逆元

ll exgcd(ll a, ll b, ll &x, ll &y) { //扩展欧几里得算法
	if(b == 0) {
		x = 1, y = 0;
		return a;
	}
	ll ret = exgcd(b, a%b, y, x);
	y -= a / b * x;
	return ret;
}
ll getInv(int a, int mod) { //求a在mod下的逆元,不存在逆元返回-1
	ll x,y;
	ll d = exgcd(a, mod, x, y);
	return d == 1 ? (x % mod + mod) % mod : -1;
}

并查集 Disjoint Set

/* 并查集模板 Disjoint Set */
int n,par[maxn],rnk[maxn];

/* 父节点和层数初始化 */
void init() {
	for(int i=0; i<=n; i++) {
		par[i] = i;
		rnk[i] = 0;
	}
}

/* 记忆化搜索 */
int find_root(int x) {
	return par[x] == x ? x : par[x] = find_root(par[x]);
}

/* 联合两个点 */
void union_vertices(int x, int y) {
	x = find_root(x);
	y = find_root(y);
	if(x == y) return;  //两点已经相连 
	/* 寻找层数小的点连,以便减少复杂度 */
	if (rnk[x] > rnk[y])
		par[y] = x;
	else if(rnk[y] > rnk[x])
		par[x] = y;
	else {
		par[x] = y;
		rnk[y]++;
	}
}

线段树

/* 线段树模板 */
int arr[maxn],tree[40*maxn];

/* 建树 */
void build_tree(int node, int start, int end) {
	if(start == end){
		tree[node] = arr[start];
	}
	else{
		int mid = (start + end) / 2;
		int left_node  = 2 * node;
		int right_node = 2 * node + 1;
		build_tree(left_node,start,mid);
		build_tree(right_node,mid+1,end);
		tree[node] = tree[left_node] + tree[right_node];
	}
}

/* 更改 */
void update_tree(int node, int start, int end, int idx, int add) {
	if(start == end) {
		tree[node] += add;
	}
	else if(idx < start || end < idx) {
		return;
	}
	else {
		int mid = (start + end) / 2;
		int left_node  = 2 * node;
		int right_node = 2 * node + 1;
		if(start <= idx && idx <=mid) {
			update_tree(left_node,start,mid,idx,add);
		}
		else {
			update_tree(right_node,mid+1,end,idx,add);
		}
		tree[node] = tree[left_node] + tree[right_node];
	}
}


/* 查找结点 */
int query_tree(int node, int start, int end, int L, int R) {
	if (R < start || end < L) {
		return 0;
	}
	else if(L <= start && end <= R) {
		return tree[node];
	}
	else {
		int mid = (start + end) / 2;
		int left_node  = 2 * node;
		int right_node = 2 * node + 1;
		int sum_left  = query_tree(left_node,start,mid,L,R);
		int sum_right = query_tree(right_node,mid+1,end,L,R);
		return sum_left + sum_right;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值