본문 바로가기
BOJ

1086. 박성원

by hyunnwoo 2023. 7. 20.

https://www.acmicpc.net/problem/1086

 

1086번: 박성원

첫째 줄에 정답을 기약분수 형태로 출력한다. p/q꼴로 출력하며, p는 분자, q는 분모이다. 정답이 0인 경우는 0/1로, 1인 경우는 1/1로 출력한다.

www.acmicpc.net

 

 

티어 : 플래5

 

정말 오랜만에 DP문제를 풀어봤다. 꽤 난이도가 있었는데, 적용되는 dp 개념자체는 어렵지 않고, 메모이제이션 해주는 방법이랑 구현 과정이 난이도가 있어 티어가 플래티넘인 것 같다.

 

메모이제이션 구현 방법이 잘 생각나지 않아 계속 고민하고 있었는데,

비트 방식으로 메모이제이션을 구현하는 아이디어를 얻어 해결할 수 있었다.

 

문제를 해결할 로직을 구체적으로 정리한 후 본격적으로 코딩을 시작하기 전에 다른 사람의 블로그 글을 참고하였는데, 이 때 "비트 방식" 4글자를 보자마자 이마를 탁 치며 코딩을 시작하였다. 좀 더 고민해서 내 스스로 이런 아이디어를 생각해냈으면 어땠을까 하는 아쉬움과 후회도 남는다.

 

백준 풀기 시작한지 얼마 안됐는데도, 요새 코드를 한 번에 완성하는 실력이 꽤 늘은게 느껴진다.

로직을 구상하고 코드를 한번에 뽑아냈을 때, 그 완성도가 점차 느는 것 같다. 수정하는 시간과 양이 줄어드는게 체감된다.

 

이번 여름 방학 기간동안 플래티넘 이상 티어의 문제들을 더 많이 도전해봐야겠다.

 

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

char s[20][55];
struct str{
    int l;
    int r;
} arr[20];

long long int dp[32770][105], dpCH[32770];
int n, k, tot_len;

int remain(int x, int i){
    for( ; i>0 ; i--){
        x *= 10;
        x %= k;
    }
    return x;
}

int mul2(int x){
    int re = 1;
    for(int i=0 ; i<x ; i++) re *= 2;
    return re;
}

long long int f(int index, int re, int len){
    if(dpCH[index] == 1) return dp[index][re];
    
    int bit = index;
    for(int i=0 ; i<n ; i++){
        if(bit % 2 == 1){
            int rem = remain(arr[i].r, len-arr[i].l);
            f(index - mul2(i), (re - rem + k) % k, len-arr[i].l);
            for(int j=0 ; j<k ; j++){
                dp[index][ (j + rem) % k ] += dp[index - mul2(i)][j];
            }
        }
        bit /= 2;
    }
    dpCH[index] = 1;
    return dp[index][re];
}

long long int nfct(int n){
    long long int re = 1;
    for(int i=1 ; i<=n ; i++) re *= i;
    return re;
}

long long int gcd(long long int x, long long int y){
    if(x == 0) return y;
    return gcd(y%x, x);
}

int main()
{
    scanf("%d", &n);
    for(int i=0 ; i<n ; i++) scanf("%s", s[i]);
    scanf("%d", &k);

    for(int i=0 ; i<n ; i++){
        arr[i].l = strlen(s[i]);
        tot_len += arr[i].l;
        for(int j=arr[i].l-1 ; j>=0 ; j--){
            arr[i].r += remain((s[i][j] - '0'), arr[i].l - j - 1);
        }
        arr[i].r %= k;
        dp[mul2(i)][arr[i].r] = 1;
        dpCH[mul2(i)] = 1;
    }

    int init = 0;
    for(int i=0 ; i<n ; i++) init += mul2(i);

    long long int output = f(init, 0, tot_len), g = gcd(f(init, 0, tot_len), nfct(n));
    printf("%lld/%lld", output/g, nfct(n)/g);
}

'BOJ' 카테고리의 다른 글

6549. 히스토그램에서 가장 큰 직사각형  (0) 2023.07.21
10868. 최솟값  (0) 2023.07.19
8980. 택배  (0) 2023.07.18
1300. K번째 수  (0) 2023.07.18
2042. 구간 합 구하기  (0) 2023.07.18