2022.5.15 AcWing周賽第51場[補]
阿新 • • 發佈:2022-05-15
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; }