Problem
https://www.acmicpc.net/problem/1513
Idea
d[x][y][c]: x,y에 왔을 때 총 들린 오락실 수가 c일 때의 총 경우의 수로 부분 정의
오락실이 증가하는 방향이어야 하므로 상태가 하나 더 필요
d[x][y][k][c]: x,y에 왔을 때 이전 들린 오락실이 k이고, 총 들린 오락실 수가 c일 때의 총 경우의 수로 부분 정의
// d[i][j][k][c] += d[i-1][j][k][c-1] + d[i][j-1][k][c-1];
f(x, y, k, c) =
f(x - 1, y, k, i) + f(x, y - 1, k, i) // 1 <= i <= C, if x=y is not game room
f(x - 1, y, j, i - 1) + f(x, y - 1, j, i - 1) // 1 <= i <= C, 0 <= j < game room, if x=y is game room
상향식
for (int i=0; i<=C; i++) {
for (int k=0; k < max(C,1); k++) {
ans[i] += d[N][M][k][i];
ans[i] %= mod;
}
printf("%d ",ans[i]);
}
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= M; j++) {
if (game[i][j] == -1) { //오락실이 아니고 하나도 안들린경우
d[i][j][0][0] += d[i-1][j][0][0] + d[i][j-1][0][0];
d[i][j][0][0] %= mod;
}
// 오락실 c개 들리는 경우
for (int c = 1; c <= C; c++) {
int gameNum = game[i][j];
if (gameNum == -1) {
// 오락실이 아니면 방문한 오락실들 확인
for (int k = 0; k <= C; k++) {
d[i][j][k][c] += d[i-1][j][k][c] + d[i][j-1][k][c];
}
} else {
if (c == 1) {
// 현위치가 오락실이고 처음방문하는 경우라면
// 이전 오락실은 0, 이전 방문 총 오락실 수 0
d[i][j][0][c] += d[i-1][j][0][0] + d[i][j-1][0][0];
} else {
for (int k = 0; k < gameNum; k++) {
d[i][j][k][c] += d[i-1][j][k][c-1] + d[i][j-1][k][c-1];
}
}
}
}
}
}
하향식
for (int i = 0; i <= c; i++) {
int ans = 0;
for (int j = 0; j <= c; j++) {
ans = f(n, m, j, i);
}
sysout(ans)
}
int f(int n int m, int k, int c) {
if (n < 1 || n > N || m < 1 || m > M) {
return 0;
}
int ret = d[n][m][k][c];
if (ret != -1) {
return ret;
}
int roomNum = game[n][m];
if (roomNum == 0) {
// 오락실이 아니면 이전과 상태변화가 없다
ret = f(n-1, m, k, c) + f(n, m-1, k, c);
} else {
if (roomNum == k) {
for (int i = 0; i < k; i++) {
// 이전은 k 보다 적어야된다
ret = f(n-1, m, i, c - 1) + f(n, m-1, i, c - 1);
}
}
}
return r;
}