1. 程式人生 > 其它 >2022.5.15 AcWing周賽第51場[補]

2022.5.15 AcWing周賽第51場[補]

A 簽到
https://www.acwing.com/problem/content/4422/

#include <bits/stdc++.h>
using namespace std;

int n;
int p, q;
int ans;

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d %d", &p, &q);
		if (p <= q - 2)
			ans++;
	}

	printf("%d\n", ans);

	return 0;
}

B 並查集

https://www.acwing.com/problem/content/4423/

本題暴力使用BFS搜尋會TLE,因為資料範圍 n <= 1e4。
可以考慮把每次BFS四個方向的ans記錄下來,下次再用。對二維陣列按照一維陣列重新編號,並記錄每個 '.' 連通塊的數量,在處理詢問時,對 '*' 的四個方向尋找其父節點,由於四個方向的 '.' 可能連成一片,所以要注意去重,再將去重後的父節點對應的s(空格連通塊數)累加起來。

#include <bits/stdc++.h>
using namespace std;

typedef pair<int, int> PII;

const int N = 1010, M = N * N;

int n, m;
char g[N][N];
int p[M], s[M];
int dx[4] = {0, 1, 0, -1};

int dy[4] = {1, 0, -1, 0};

int get(int x, int y) {
	return x * m + y;
}

int find(int x) {
	if (p[x] != x)
		p[x] = find(p[x]);
	return p[x];
}
/*
int bfs(int x, int y) {
	int res = 0;

	queue<PII> q;
	q.push({x, y});
	while (!q.empty()) {
		auto t = q.front();
		q.pop();
//		if (x == 2 && y == 1) {
//			printf("%d %d\n", t.first, t.second);
//		}
		if (!st[t.first][t.second])
			res++;
		st[t.first][t.second] = true;
		for (int i = 0; i < 4; i++) {
			int nx = t.first + dx[i];
			int ny = t.second + dy[i];

			if (nx < 0 || nx >= n || ny < 0 || ny >= m)
				continue;
			if (g[nx][ny] != '.')
				continue;
			if (st[nx][ny])
				continue;

			q.push({nx, ny});
		}
	}

	return res;
}
*/
int main() {
	scanf("%d %d", &n, &m);
	for (int i = 0; i < n; i++)
		scanf("%s", g[i]);
	for (int i = 0; i < n * m; i++)
		p[i] = i, s[i] = 1;


	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			if (g[i][j] == '.') {
				for (int k = 0; k < 4; k++) {
					int x = i + dx[k], y = j + dy[k];
					if (x >= 0 && x < n && y >= 0 && y < m && g[x][y] == '.') {
						int a = get(i, j), b = get(x, y);
						a = find(a), b = find(b);
						if (a != b) {
							s[b] += s[a];
							p[a] = b;
						}
					}
				}
			}
		}
	}

	for (int i = 0; i < n; i ++ ) {
		for (int j = 0; j < m; j ++ )
			if (g[i][j] == '.')
				printf(".");
			else {
				int fathers[4], cnt = 0;
				for (int k = 0; k < 4; k ++ ) {
					int x = i + dx[k], y = j + dy[k];
					if (x >= 0 && x < n && y >= 0 && y < m && g[x][y] == '.') {
						int a = get(x, y);
						fathers[cnt ++ ] = find(a);
					}
				}

				int sum = 1;
				if (cnt) {
					// 防止區間重複
					sort(fathers, fathers + cnt);
					cnt = unique(fathers, fathers + cnt) - fathers;
					for (int k = 0; k < cnt; k ++ )
						sum += s[fathers[k]];
				}

				printf("%d", sum % 10);
			}
		puts("");
	}

	return 0;
}

C 重複覆蓋問題 貪心問題

https://www.acwing.com/problem/content/4424/

按題意來說,是重複覆蓋問題,但是由於本題是線性遞增的,從前向後列舉時,如果前面的不能覆蓋,則後面的也一定不能覆蓋,同時後面的結點能覆蓋的右端點大於前面結點能覆蓋的右端點,因此可以轉化為貪心問題。

#include <bits/stdc++.h>
using namespace std;

/*
重複覆蓋問題

但是,由於該問題是線性問題,可以轉化成貪心問題。
*/

const int N = 1010;

int n, r;
int q[N], cnt;

int main() {
	scanf("%d %d", &n, &r);
	for (int i = 1; i <= n; i++) {
		int tmp;
		scanf("%d", &tmp);
		if (tmp)
			q[cnt++] = i;
	}

	int res = 0, last = 0;
	for (int i = 0; i < cnt; i++) {
		if (last >= n)
			break;

		if (q[i] - r > last) {
			res = -1;
			break;
		}

		int j = i;
		while (j + 1 < cnt && q[j + 1] - r <= last)
			j++;
		last = q[j] + r - 1;
		res++;
		i = j;
	}

	if (last < n)
		res = -1;
	printf("%d\n", res);

	return 0;
}