GENIUS (중, p. 359)

문제#

image.png


어떻게 풀었나?#

처음에는 상태공간을 dp[노래 번호][분] = 노래 번호가 x분에 play중일 확률로 잡고 dp[0][L[0]-1]까지 1.0을 대입하여 초기화 한 뒤 반복문 DP로 답을 구하려고 했다. 하지만, 예시 출력 결과가 다른 것을 보고 뭔가 잘못됐다는 것을 깨달았다.

잘 생각해보니, 4분짜리 30번 곡을 play중이고 현재 1분정도 들었는데, 2분짜리 28번 곡을 play중일 확률은 0일 수밖에 없는데, 위의 방식대로라면 dp[28][3] = dp[30][1]*T[30][28] 로 답을 구하게 된다.

그래서 상태공간을 dp[노래 번호][분] = 노래 번호가 x분에 play가 끝날 확률로 잡았더니 AC를 받을 수 있었다.

image1.png


정답 코드#

#include <bits/stdc++.h>
using namespace std;
int N, K, M;
int L[51];
double T[51][51];
int Q[51];
const int MASK = (1 << 4) - 1;
double dp[MASK + 1][51];
void Init() {
    for(int i = 0; i <= MASK; i++) {
        for(int j = 0; j <= 50; j++) {
            dp[i][j] = 0;
        }
    }
}
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    int tc; cin >> tc;
    while(tc--) {
        cin >> N >> K >> M;
        for(int i = 0; i < N; i++) {
            cin >> L[i];
        }
        for(int i = 0; i < N; i++) {
            for(int j = 0; j < N; j++) {
                cin >> T[i][j];
            }
        }
        for(int i = 0; i < M; i++) {
            cin >> Q[i];
        }

        Init();
        dp[L[0]][0] = 1.0;
        for(int s = L[0] + 1; s <= K + 4; s++) {
            for(int i = 0; i < N; i++) {
                if(s - L[i] < 0) continue;
                double& res = dp[s & MASK][i];
                res = 0;
                for(int j = 0; j < N; j++) {
                    // j->i
                    res += dp[(s - L[i]) & MASK][j] * T[j][i];
                }
            }
        }
        for(int i = 0; i < M; i++) {
            double sum = 0;
            for(int j = K + 1; j <= K + 4; j++) {
                if(j - L[Q[i]] <= K) {
                    if(dp[j & MASK][Q[i]]) {
                        sum += dp[j & MASK][Q[i]];
                    }
                }
            }
            printf("%.8lf ", sum);
        }
        puts("");
    }
    return 0;
}