Skip to content

Commit 85db486

Browse files
committed
풀이: AtCoder Beginner Contest 446/E
?: 나머지 & 방문 DFS을 이용해 풀이
1 parent ae5c6c2 commit 85db486

3 files changed

Lines changed: 182 additions & 0 deletions

File tree

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# E - Multiple-Free Sequences
2+
3+
[링크](https://atcoder.jp/contests/abc446/tasks/abc446_e)
4+
5+
| 난이도 |
6+
| :----: |
7+
| 450 |
8+
9+
## 설계
10+
11+
### 시간 복잡도
12+
13+
입력받은 수를 M, A, B라 하자.
14+
15+
각 숫자 순열에 대해서 M으로 떨어지는지 확인해야하며, 각 과정마다 나머지값만을 사용할 수 있다.
16+
17+
이 경우 총 경우의 수를 계산하는데 O(M^2)의 시간 복잡도를 사용한다.
18+
19+
### 공간 복잡도
20+
21+
각 숫자 쌍에 대해서 방문 여부를 저장하는데 O(M^2)의 공간 복잡도를 사용한다.
22+
23+
### 나머지 & 방문 DFS
24+
25+
| 내 코드 (ms) | 시간 복잡도 | 공간 복잡도 |
26+
| :----------: | :---------: | :---------: |
27+
| 16 | O(M^2) | O(M^2) |
28+
29+
A, B값은 고정되며 0 ~ (M-1) 범위의 x, y 쌍에 대해서 생성되는 순열을 확인한다.
30+
31+
이 때 각 순열의 값이 M으로 떨어지는지만 확인하면 되므로 각 순열의 값에서 M으로 나눈 나머지만을 사용할 수 있다.
32+
33+
또한 각 순열을 생성할 때 현재값과 직전값만을 사용하므로 해당 두 값의 경우의 수를 다음과 같이 제한할 수 있다.
34+
35+
- x는 0 ~ (M-1) 범위의 값
36+
- y는 0 ~ (M-1) 범위의 값
37+
38+
따라서 모든 경우의 수에 대해 M으로 떨어지는지 DFS로 순열을 생성하며 확인할 수 있다.
39+
40+
이 때 방문배열을 이용해 해당 쌍이 이미 안전한지, 위험한지, 방문중인지 등을 저장하여 중복 계산을 방지할 수 있다.
41+
42+
모든 쌍에 대해서 DFS를 수행한 후 안전한 쌍의 개수를 세어 반환한다.
43+
44+
```cpp
45+
long long solution(int m, int a, int b) {
46+
long long answer = 0;
47+
48+
// 0 = unvisited
49+
// 1 = visiting
50+
// 2 = safe
51+
// 3 = bad
52+
vector<vector<int>> state(m, vector<int>(m, 0));
53+
54+
function<bool(int, int)> recursive = [&](int x, int y) {
55+
if (x == 0 || y == 0) return false;
56+
57+
if (state[x][y] == 2) return true;
58+
if (state[x][y] == 3) return false;
59+
if (state[x][y] == 1) {
60+
return true;
61+
}
62+
state[x][y] = 1;
63+
64+
int nx = y;
65+
int ny = ((long long)a * y + (long long)b * x) % m;
66+
67+
bool isFine = recursive(nx, ny);
68+
69+
state[x][y] = isFine ? 2 : 3;
70+
return isFine;
71+
};
72+
73+
for (int x = 0; x < m; x++) {
74+
for (int y = 0; y < m; y++) {
75+
if (state[x][y] == 0) {
76+
recursive(x, y);
77+
}
78+
}
79+
}
80+
81+
for (int x = 0; x < m; x++) {
82+
for (int y = 0; y < m; y++) {
83+
if (state[x][y] == 2) {
84+
answer++;
85+
}
86+
}
87+
}
88+
89+
return answer;
90+
}
91+
```
92+
93+
## 고생한 점
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#include <algorithm>
2+
#include <climits>
3+
#include <cmath>
4+
#include <cstring>
5+
#include <functional>
6+
#include <iostream>
7+
#include <map>
8+
#include <numeric>
9+
#include <queue>
10+
#include <set>
11+
#include <stack>
12+
#include <string>
13+
#include <unordered_map>
14+
#include <unordered_set>
15+
#include <vector>
16+
17+
using namespace std;
18+
19+
long long solution(int m, int a, int b) {
20+
long long answer = 0;
21+
22+
// 0 = unvisited
23+
// 1 = visiting
24+
// 2 = safe
25+
// 3 = bad
26+
vector<vector<int>> state(m, vector<int>(m, 0));
27+
28+
function<bool(int, int)> recursive = [&](int x, int y) {
29+
if (x == 0 || y == 0) return false;
30+
31+
if (state[x][y] == 2) return true;
32+
if (state[x][y] == 3) return false;
33+
if (state[x][y] == 1) {
34+
return true;
35+
}
36+
state[x][y] = 1;
37+
38+
int nx = y;
39+
int ny = ((long long)a * y + (long long)b * x) % m;
40+
41+
bool isFine = recursive(nx, ny);
42+
43+
state[x][y] = isFine ? 2 : 3;
44+
return isFine;
45+
};
46+
47+
for (int x = 0; x < m; x++) {
48+
for (int y = 0; y < m; y++) {
49+
if (state[x][y] == 0) {
50+
recursive(x, y);
51+
}
52+
}
53+
}
54+
55+
for (int x = 0; x < m; x++) {
56+
for (int y = 0; y < m; y++) {
57+
if (state[x][y] == 2) {
58+
answer++;
59+
}
60+
}
61+
}
62+
63+
return answer;
64+
}
65+
66+
int main() {
67+
ios_base ::sync_with_stdio(false);
68+
cin.tie(NULL);
69+
cout.tie(NULL);
70+
71+
cout.precision(10);
72+
73+
// freopen("./input.txt", "r", stdin);
74+
75+
int M, A, B;
76+
cin >> M >> A >> B;
77+
78+
auto answer = solution(M, A, B);
79+
80+
cout << answer << endl;
81+
// cout << (answer ? "Yes" : "No") << endl;
82+
// for (auto &line : answer) {
83+
// cout << line << "\n";
84+
// }
85+
// cout << endl;
86+
87+
return 0;
88+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1000 784 385

0 commit comments

Comments
 (0)