※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※
이번에 볼 문제는 백준 16650번 문제인 Counting Stairs이다.
문제는 아래 링크를 확인하자.
https://www.acmicpc.net/problem/16650
16650번: Counting Stairs
For each test case, output a line with a single integer — the number of symmetric stairs with exactly ni cubes, modulo 998 244 353.
www.acmicpc.net
문제에서 찾아야하는 계단 모양들은 맨 왼쪽 아래 칸을 포함하는 가장 큰 정사각형 S와 윗 부분 A, 오른쪽 부분 B의 세 부분으로 분리하여 생각할 수 있다.
주어지는 블럭의 개수 N에서 S를 구성하는 블럭의 개수를 뺀 개수가 홀수라면 A와 B를 개수가 같게 구성할 수 없으므로, N이 홀수이면 S의 변의 길이는 홀수, N이 짝수이면 S의 변의 길이는 짝수가 되어야 한다.
A 하나를 구성하는 블럭의 개수를 X, S의 변의 길이를 K라 하자. 이 때, A를 구성하는 방법은 "X를 K개의 (0 이상의 정수)로 분할하는 경우의 수", 즉 "X+K를 K개의 (1 이상의 정수)로 분할하는 경우의 수"와 같다.
n을 k개의 1 이상의 정수로 분할하는 경우의 수를 P(n,k)라 할 때, P(n,k) = P(n-k,k) + P(n-1,k-1) 과 같은 점화관계가 성립한다는 사실은 잘 알려져있다. (초기값은 P(0,0) = 1, 그 외 n<1 또는 k<1인 경우 P(n,k) = 0이다.) 메모이제이션을 잘 하여 위의 식을 이용해 문제를 해결하자.
이 문제에서 K는 sqrt(N)을 넘을 수 없으므로, 최악의 경우 직접 조사하게 되는 P(n,k)의 값의 가짓수는 약 Nsqrt(N)가지가 된다. 이는 문제 해결에 충분한 가짓수이다.
아래는 제출한 소스코드이다.
#define MOD 998244353
#include <iostream>
#include <vector>
using namespace std;
int dp[200001][448];
int partition(int N, int K) {
if (N < K) return 0;
if (N <= 0 || K <= 0) {
if (N == 0 && K == 0) return 1;
return 0;
}
int& dpNK = dp[N][K];
if (dpNK) return dpNK;
dpNK = partition(N - K, K) + partition(N - 1, K - 1);
if (dpNK >= MOD) dpNK -= MOD;
return dpNK;
}
void solve() {
int N; cin >> N;
int ans = 0;
if (N & 1) {
for (int i = 1; i * i <= N; i += 2) {
int tmp = (N - i * i) >> 1;
ans += partition(tmp + i, i);
if (ans >= MOD) ans -= MOD;
}
}
else {
for (int i = 2; i * i <= N; i += 2) {
int tmp = (N - i * i) >> 1;
ans += partition(tmp + i, i);
if (ans >= MOD) ans -= MOD;
}
}
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
int T; cin >> T;
while (T--) {
solve();
}
}
'BOJ' 카테고리의 다른 글
[BOJ 14004 // C++] ICPC (0) | 2022.05.11 |
---|---|
[BOJ 1013 // C++] Contact (0) | 2022.05.10 |
[BOJ 7562 // C++] 나이트의 이동 (0) | 2022.05.08 |
[BOJ 24389 // C++] 2의 보수 (1) | 2022.05.08 |
[BOJ 20867 // C++] Rulltrappa (0) | 2022.05.08 |