일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
Tags
- 그리디
- ccw 알고리즘
- Express.js
- 트라이
- Keys
- join(조인)
- PROJECT
- insomnia
- outer join(외부 조인)
- map
- ERD
- 자바스크립트
- pm2
- JavaScript
- Next
- HTTP
- DP
- MySQL
- trie
- Prisma
- 그래프 탐색
- MongoDB
- 게임 서버 아키텍처
- branch
- string
- router
- 이분 탐색
- html5
- localstorage
- Github
Archives
- Today
- Total
dh_0e
[PS] 박성원 / C++ (백준 1086번) 본문


비트마스킹을 활용한 dp 문제, 근데 이제 큰 수 % k를 곁들인 ..
시행 착오
vector<pair<int, int> > dp[][]로 선언을 하여 dp[i][j] = i개의 원소를 합쳤을 때, 마지막 원소에 j번째 원소를 삽입한 pair(first = 지금까지 삽입한 원소들의 비트마스킹, second = k로 나눈 나머지)를 삽입하는 것으로 점화식을 짰다.
이 후에 말도 안 되는 메모리 초과를 보여주며 전처리 및 메모리도 줄인 후 진행했는데 여전히 답이 안 보였다.
해결 방안
갈아엎었다. 점화식부터 다시 구상하니 dp[i][j] = 지금까지 사용한 원소를 마스킹한 값이 i, 나머지가 j인 수열의 갯수 로 풀 수 있었다.
- 전처리 및 dp에 각각 하나씩 사용한 경우의 수 저장
- ten_mod에 10^l 들을 k로 나눈 나머지를 모두 구해놓는다. 이때, 0<= l <= 750 (최대 n 크기 * 각 수의 최대 길이)
- element_mod엔 입력 받은 값들을 k로 나눈 나머지를 ten_mod를 이용해 구해놓는다. (mod_ 함수)
- dp[1<<i][element[i]를 나눈 나머지]에 1 저장 (digit[i][j] = dp[i][j]의 지금까지 자릿수)
- 나머지 연산은 분배법칙이 성립하는 성질을 이용해 dp를 끝(1<<n - 1)까지 구한다.
- dp[(1<<n)-1][0] 값과 factorial(n) 값의 최대 공약수를 구해서 문제 조건에 맞게 출력
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
ll mod_(string str);
ll gcd(ll a, ll b);
int n, k;
ll ten_mod[751], element_mod[16];
string element[16];
ll dp[39993][101], digit[39993][101];
int main()
{
scanf("%d", &n);
for (int i = 0; i < n; i++) cin >> element[i];
scanf("%d", &k);
ll temp = 1;
for (int i = 0; i < 751; i++) {
ten_mod[i] = temp % k;
temp = temp * 10 % k;
}
for (int i = 0; i < n; i++) {
ll mod_val = mod_(element[i]);
dp[1 << i][mod_val] = 1;
digit[1 << i][mod_val] = element[i].size();
element_mod[i] = mod_val;
}
for (int mask = 1; mask < (1 << n); mask++) {
for (int i = 0; i < k; i++) {
if (dp[mask][i]) {
for (int j = 0; j < n; j++) {
ll new_mask = mask | (1 << j), mod;
if (new_mask == mask)continue;
mod = (i + (element_mod[j] * ten_mod[digit[mask][i]]) % k) % k;
dp[new_mask][mod] += dp[mask][i];
digit[new_mask][mod] = digit[mask][i] + element[j].size();
}
}
}
}
ll numerator = dp[(1 << n) - 1][0], denominator = 1;
for (int i = 1; i <= n; i++) denominator *= i;
if (numerator == 0) {
printf("0/1\n");
return 0;
}
ll gcd_ = gcd(denominator, numerator);
printf("%lld/%lld\n", numerator / gcd_, denominator / gcd_);
return 0;
}
ll mod_(string str) {
ll hap = 0;
for (int i = 0; i < str.size(); i++) {
hap += (str[i] - '0') * ten_mod[str.size() - i - 1];
hap %= k;
}
return hap;
}
ll gcd(ll a, ll b) {
while (b != 0) {
ll temp = a % b;
a = b;
b = temp;
}
return a;
}
'알고리즘 > Baekjoon' 카테고리의 다른 글
[PS] 뱀과 사다리 게임 / C++ (백준 16928번) (0) | 2025.04.09 |
---|---|
[PS] 너 봄에는 캡사이신이 맛있단다 / C++ (백준 15824번) (0) | 2025.04.02 |
[PS] 두 배열의 합 / C++ (백준 2143번) (0) | 2025.03.20 |
[PS] GCD(n, k) = 1 / C++ (백준 11689번) (0) | 2025.03.14 |
[PS] 철로 / C++ (백준 13334번) (0) | 2025.03.13 |