算法杂项~

1.并查集

具体介绍:

【算法与数据结构】—— 并查集-CSDN博客

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 101;

int pre[N], a[N], lev[N];
int n;

void Init()
{
	for (int i = 0; i < n; i++) pre[i] = i, lev[i] = 1;
	for (int i = 0; i < n; i++) scanf("%d", &a[i]);
}

int Find(int x)
{
	if (x != pre[x]) return pre[x] = Find(pre[x]);
	return pre[x];  
}

void Union(int a, int b)
{
	if (lev[a] <= lev[b]) pre[a] = b;
	else pre[b] = a;
}

int main()
{
	cin >> n;
	Init();
}​

2.快速幂

用途:用于快速的求某数的幂

原理分析:

快速幂,龟速乘和快速乘_海龟编辑器a的b次方怎么求-CSDN博客

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;
LL a, b;

LL f(LL a, LL b)
{
	LL res = 1;

	while (b)
	{
		if (b & 1) res *= a;
		b >>= 1;
		a *= a;
	}
	return res;
}

int main()
{
	cin >> a >> b;
	cout << f(a, b);
}

3.龟速乘

用途:可以慢慢的求值与值的乘积,防止爆变量的最大长度(比如爆int)

原理分析:

快速幂,龟速乘和快速乘_海龟编辑器a的b次方怎么求-CSDN博客

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;
LL a, b;

LL f(LL a, LL b)
{
	LL res = 0;

	while (b)
	{
		if (b & 1) res += a;
		b >>= 1;
		a += a;
	}
	return res;
}

int main()
{
	cin >> a >> b;
	cout << f(a, b);
}

4.快速幂取模

用途:在快速幂上进行取模操作

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;
LL a, b, mod;

LL f(LL a, LL b, int mod)
{
	LL res = 1;

	while (b)
	{
		if (b & 1) res = (res * a) % mod;
		b >>= 1;
		a = (a * a) % mod;
	}
	return res;
}


int main()
{
	cin >> a >> b >> mod;
	cout << f(a, b, mod);
}

5.龟速乘取模

用途:在龟速乘上进行取模操作

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

LL a, b, mod;

LL f(LL a, LL b, int mod)
{
	LL res = 0;

	while (b)
	{
		if (b & 1) res = (res + a) % mod;
		b >>= 1;
		a = (a + a) % mod;
	}
	return res;
}

int main()
{
	cin >> a >> b >> mod;
	cout << f(a, b, mod);
}

6.快速幂取模优化(结合龟速乘取模)

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

LL a, b, mod;

LL f1(LL a, LL b, int mod)
{
	LL res = 0;

	while (b)
	{
		if (b & 1) res = (res + a) % mod;
		b >>= 1;
		a = (a + a) % mod;
	}
	return res;
}

LL f2(LL a, LL b, int mod)
{
	LL res = 1;

	while (b)
	{
		if (b & 1) res = f1(a, b, mod) % mod;
		b >>= 1;
		a = f1(a, a, mod) % mod;
	}
	return res;
}

int main()
{
	cin >> a >> b >> mod;
	cout << f2(a, b, mod);
}

7.矩阵快速幂

就是把快速幂中的数字换成了矩阵

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

#define MAX 100

struct Martix 
{
	int row;	// 行 
	int col;	// 列 
	int martix[MAX][MAX];

	Martix(int r, int c) : row(r), col(c) {} // 构造函数 
};

Martix Multiply(Martix x, Martix y)//求两个矩阵的乘积
{
	Martix z(x.row, y.col);

	for (int i = 0; i < z.row; i++) 
	{
		for (int j = 0; j < z.col; j++) 
		{
			z.martix[i][j] = 0;
			for (int k = 0; k < x.col; k++)
				z.martix[i][j] += x.martix[i][k] * y.martix[k][j];
		}
	}

	return z;
}

Martix Power(Martix x, int k)
{
	Martix r(x.row, x.col);

	// 单位矩阵构建 
	for (int i = 0; i < r.row; i++) 
	{
		for (int j = 0; j < r.col; j++) 
		{
			if (i == j) r.martix[i][j] = 1;
			else r.martix[i][j] = 0;
		}
	}

	// 矩阵快速幂 
	while (k != 0) 
	{
		if (k & 1)
			r = Multiply(x, r);
		k = k >> 1;
		x = Multiply(x, x);
	}

	return r;
}

int main()
{
	int r, k;

	printf("请输入行(列):\n");
	scanf("%d", &r);
	Martix x(r, r);

	printf("请输入%d行%d列的矩阵:\n", r, r);
	for (int i = 0; i < x.row; i++)
		for (int j = 0; j < x.col; j++)
			scanf("%d", &x.martix[i][j]);

	printf("请输入指数k:\n");
	scanf("%d", &k);

	Martix result = Power(x, k);

	printf("结果是:\n");
	for (int i = 0; i < result.row; i++) 
	{
		for (int j = 0; j < result.col; j++)
			printf("%d ", result.martix[i][j]);
		printf("\n");
	}
}​

8.一维前缀和

用途:方便对一位数组进行区间处理

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 1e5 + 10;

int s[N], n, temp;//s[N]是前缀和数组

int main()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		scanf("%d", &temp);
		s[i] = s[i - 1] + temp;//求一维前缀和
	}

	for (int i = 1; i <= n; i++) printf("%d ", s[i] - s[i - 1]);//可以原来求原数组每一项
}

9.二维前缀和

用途:同一维数组

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 1e3 + 10;

int s[N][N], n, m ,temp;//s[N]是前缀和数组

int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			scanf("%d", &temp);
			s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + temp;//求二维前缀和
		}
	}

	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			printf("%d ", s[i][j] - s[i - 1][j] - s[i][j - 1] + s[i - 1][j - 1]);//也可以取原二维数组的每一项
		}
		cout << endl;
	}
}

10.树状数组

用途:同前缀和,但是搜索时更快

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 1e3 + 10;

int tree[N], n, temp;


int Lowbit(int x)//求出下标位x的项维护了多长的序列,比如下标为12=0b1100,二进制中存在2个0,那么它维护的序列长度就是2的2次方,即4这么长
//也即求出下标为x的元素在树的第几层且距离其父/子节点的距离是多少
//比如x=12(0b1100),那么return 4(12的二进制后面有两个0,即处在树的第二层,所以返回二进制的100即返回4)
{
	return x & -x;
}

void Add(int x, int y)
//对树状数组进行修改操作,主要是修改下标为x的元素和其父节点(还有父父……节点)的元素
{
	for (int i = x; i <= n; i += Lowbit(i)) tree[i] += y;
}

int Sum(int x)
//求前缀和
{
	int res = 0;
	for (int i = x; i > 0; i -= Lowbit(i)) res += tree[i];
	return res;
}

int main()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		scanf("%d", &temp);
		Add(i, temp);//初始化树状树状
	}

	for (int i = 1; i <= n; i++) printf("%d ", Sum(i) - Sum(i - 1));//可以求出来每一项的值
}

11.线段树

用途:同前缀和,但是搜索时更快

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

#define INF 1e8
const int N = 1e3 + 10;

struct Tree
{
	int l, r;
	int sum = 0;
}tr[N];

int arr[N], n, temp;

void Push_up(int u)//用于通过树的叶节点为上层的节点赋值和更新值
{
	tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}

void Build(int u, int l, int r)//创建线段树,u是当前节点下标,l,r是当前节点的左右端点
{
	if (l == r) tr[u] = { l,r,arr[l] };//如果l==r,说明已经递归到叶节点,可以开始赋值
	else
	{
		tr[u] = { l,r };//不是叶节点的节点,先赋值l,r,而sum需要通过Push_up()来完成
		int mid = l + r >> 1;
		Build(u << 1, l, mid);
		Build(u << 1 | 1, mid + 1, r);
		Push_up(u);//给非叶节点赋值sum
	}
}

int GetSum(int u, int l, int r)//获得某一段的数组和,u是当前节点下标,l,r是所需要的一段的左右端点
{
	if (l <= tr[u].l && r >= tr[u].r) return tr[u].sum;//如果此时需要的这一段的左右端点已经包含当前这一段,那么返回这一段的sum
	else//否则不断查找,直到把所有的所需要的这一段的值全部获得
	{
		int sum = 0;
		int mid = tr[u].l + tr[u].r >> 1;
		if (l <= mid) sum += GetSum(u << 1, l, r);
		if (r > mid) sum += GetSum(u << 1 | 1, l, r);
		return sum;
	}
}

void Add(int u, int x, int y)//更新元素,u是当前节点下标,x是目标节点,y是需要加上的值
{
	if (tr[u].l == tr[u].r) tr[u].sum += y;//先对叶节点进行更新,然后才能更新该叶节点的各级父节点
	else
	{
		int mid = tr[u].l + tr[u].r >> 1;//查找下标为x的叶节点
		if (x <= mid) Add(u << 1, x, y);
		else if (x > mid)Add(u << 1 | 1, x, y);
		Push_up(u);//逐级更新父节点
	}
}

int main()
{
	cin >> n;
	for (int i = 1; i <= n; i++) scanf("%d", &arr[i]);

	Build(1, 1, n);

	for (int i = 1; i <= n; i++) printf("%d ", GetSum(1,i,i));//输出原数组的每一项
}

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值