Hướng dẫn giải của [200 đề thầy Đức] Bài 188: Đổi sách
Chỉ dùng lời giải này khi không có ý tưởng, và đừng copy-paste code từ lời giải này. Hãy tôn trọng người ra đề và người viết lời giải.
Nộp một lời giải chính thức trước khi tự giải là một hành động có thể bị ban.
Nộp một lời giải chính thức trước khi tự giải là một hành động có thể bị ban.
Hướng dẫn giải
Phép đổi sách theo hoán vị ~p~ đi theo chu trình. Số ngày để cuốn sách của đứa trẻ ~i~ quay về ~i~ chính là độ dài chu trình chứa ~i~.
Sub 1: Vét cạn — ~O(n^2)~, dùng khi ~n \le 50~
Với mỗi ~i~, đi theo ~p~ cho đến khi quay về ~i~ và đếm số bước. Nếu chỉ nộp sub này: đúng 21/21 test.
Sub 2: Duyệt từng chu trình — ~O(n)~
Duyệt từng chu trình một lần, đánh dấu các phần tử đã thăm. Mọi phần tử trong cùng một chu trình có chung độ dài bằng số phần tử của chu trình đó. Nếu chỉ nộp sub này: đúng 21/21 test.
Chương trình hoàn chỉnh
main đọc ~q~ truy vấn. Với mỗi truy vấn, nếu ~n \le 50~ thì gọi sub1, ngược lại gọi sub2.
#include <bits/stdc++.h>
using namespace std;
int n;
int p[205]; // p[i]: đứa trẻ nhận sách từ đứa trẻ i mỗi ngày
// Sub 1: vét cạn O(n^2). Với mỗi i, đi theo p cho đến khi quay lại i.
void sub1() {
for (int i = 1; i <= n; i++) {
int cnt = 1, j = p[i];
while (j != i) {
j = p[j];
cnt++;
}
printf("%d%c", cnt, i == n ? '\n' : ' ');
}
}
// Sub 2: O(n). Mỗi chu trình của hoán vị có độ dài đúng bằng số ngày sách quay về.
// Duyệt từng chu trình một lần, gán độ dài cho mọi phần tử trong chu trình đó.
void sub2() {
vector<int> len(n + 1, 0);
for (int i = 1; i <= n; i++) {
if (len[i]) continue;
vector<int> cyc;
int j = i;
while (!len[j]) {
len[j] = -1; // đánh dấu đang thăm (để không lặp lại)
cyc.push_back(j);
j = p[j];
}
int L = cyc.size();
for (int v : cyc) len[v] = L;
}
for (int i = 1; i <= n; i++) printf("%d%c", len[i], i == n ? '\n' : ' ');
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int q;
cin >> q;
while (q--) {
cin >> n;
for (int i = 1; i <= n; i++) cin >> p[i];
if (n <= 50) sub1(); // dữ liệu nhỏ: vét cạn
else sub2();
}
return 0;
}
Bình luận