0
点赞
收藏
分享

微信扫一扫

算法刷题记录(Day 1)

天天天蓝loveyou 2022-02-22 阅读 69

The triangle(1163)

原题链接
题目类型:动态规划
使用两个而为的数组,a[][]用来存储本身具有的值,b[i][j]代表最后经过第i行第j列的最大值。
则存在递推公式b[i][j]=max(b[i-1][j],b[i-1][j-1])(注意需要判断i-1和j-1的范围,具体为i-1>0且0<j-1<=i-1)

#include<iostream>
using namespace std;
#define NMAX 102
int a[NMAX][NMAX], b[NMAX][NMAX];
int N;
int main() {
	cin >> N;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j <= i; j++) {
			cin >> a[i][j];
		}
	}

	b[0][0] = a[0][0];
	for (int i = 1; i < N; i++) {
		for (int j = 0; j <= i; j++) {
			b[i][j] = 0;
			if (j - 1 >= 0 && j - 1 <= i - 1) b[i][j] = max(b[i][j], b[i - 1][j - 1]);
			if (j >= 0 && j <= i - 1) b[i][j] = max(b[i][j], b[i - 1][j]);
			b[i][j] += a[i][j];
		}
	}

	/*for (int i = 0; i < N; i++) {
		for (int j = 0; j <= i; j++) {
			cout << b[i][j] << " ";
		}
		cout << endl;
	}*/
	int res = 0;
	for (int i = 0; i < N; i++) {
		res = max(res, b[N - 1][i]);
	}
	cout << res;
}

A Simple Problem with Integers(3468)

原题链接
题目类型:树状数组 区间修改 区间查询
在这里插入图片描述
假设给定序列为a,则d[j]=a[j]-a[j-1],d[1]=a[1],换言之,a[i]为d[1]到d[i]的和。因此,当需要进行[l,r]区间增加c时,仅仅只需d[l]加上c,d[r-1]减去c;当需要进行区间查询时,则应该遵循如上所示的公式。
因此,需要维护的是d[i]的前缀和sum1和d[i]*i的前缀和sum2,通过前缀和可以实现快速的区间和的查询。
进一步地,在对于d[i]的修改上需要进一步地对多个sum1和sum2进行修改。
注意使用在维护前缀和中的lowbit的概念
易错点:
1.树状数组都是从1开始的而不是0,因此在进行数组的存储时应该要注意是从1开始存储的
2.由于题目中有对数据范围的限制,因此需要关注各个类型的取值范围

#include<iostream>
using namespace std;
#define NMAX 100005
typedef long long ll;
int N, Q;
int A[NMAX];
int B[NMAX];
ll sum1[NMAX];
ll sum2[NMAX];
int lowbit(int x) {
	return x & -x;
}

ll ask(int x) {
	ll res = 0;
	for (int i = x; i>0; i -= lowbit(i)) {
		res += (x + 1) * sum1[i] - sum2[i];
	}
	return res;
}
ll Range_ask(int l, int r) {
	return ask(r) - ask(l - 1);//在ask中会去处理l-1为负数的情况
}

void add(int p, int x) {
	for (int i = p; i <= N; i += lowbit(i)) {
		sum1[i] += x;
		sum2[i] += p * x;
	}
}
void Range_add(int l, int r, int x) {
	add(l, x);
	add(r + 1, -x);
}
int main() {

	cin >> N >> Q;
	for (int i = 1; i <= N; i++) {
		cin >> A[i];
		sum1[i] = sum2[i] = 0;
		if (!i) B[i] = sum1[i] = sum2[i] = A[i];
		else B[i] = A[i] - A[i - 1];
		for (int j = i; j >= i - lowbit(i) + 1; j--) sum1[i] += ll(B[j]), sum2[i] += ll(ll(B[j]) * j);
	}
	/*
	for (int i = 1; i <= N; i++) {
		cout << B[i] << " " << sum1[i] << " " << sum2[i] << endl;
	}*/

	for (int i = 0; i < Q; i++) {
		getchar();//读取末尾的换行符
		char c = getchar();
		if (c == 'Q') {
			int a, b;
			cin >> a >> b; //注意a,b在数组中应该减去1
			cout << Range_ask(a, b) << endl;

		}
		else {
			int a, b, c;
			cin >> a >> b >> c;
			Range_add(a, b, c);
		}
	}
}

Ubiquitous Religions

原题链接
题目类型:并查集
易错点;
1.由于题目是多组测试,因此需要注意初始化的问题
2.学生编号从1开始而不是0,在进行存储的时候需要注意
3.最后的输出只有一个空格

#include<iostream>
using namespace std;
#define NMAX 50004
int n, m;
int Fa[NMAX];
int rd = 0;
int find(int x) {
	if (x != Fa[x]) Fa[x] = find(Fa[x]);
	return Fa[x];
}
int main() {
	while (1) {
		cin >> n >> m;
		rd++;
		if (n == 0 && m == 0) break;
		for (int i = 1; i <= n; i++) Fa[i]=i;
		for (int i = 0; i < m; i++) {
			int a, b;
			cin >> a >> b;
			Fa[b] = find(a);
		}

		int res = 0;
		for (int i = 1; i <= n; i++) {
			if (Fa[i] == i) res++;
		}
		cout << "Case "<<rd<<": " << res << endl;
	}
}

总结:

今日所遇之题皆为模板题,复习了一遍以前的知识。
Anyway,千里之行始于足下。

举报

相关推荐

0 条评论