알고스팟 문제 링크: https://algospot.com/judge/problem/read/CHRISTMAS
algospot.com :: CHRISTMAS
크리스마스 인형 문제 정보 문제 크리스마스를 맞이하여 산타 할아버지는 전세계의 착한 어린이 K명에게 인형을 사주려고 한다. 산타 할아버지는 인형을 구입하기 위해서 유명한 인형가게인 "
algospot.com
상자마다 인형이 담겨있는 갯수가 각각 다르게 주어졌을때, 아이들k명에게 똑같은 갯수의 인형을 남는 인형 없이 나누어 주려 한다.
주문을 할때 'h번 상자부터 t번 상자까지 다 주세요'(h<=t)라고만 할 수있다.
한번 만 주문할 수 있는 경우 가능한 주문 방법,
한 상자가 주문에 중복으로 포함 되지 않게끔 여러번 주문 할수 있는 경우 최대 주문 횟수, 이렇게 두가지를 구하는 문제이다.
h에서 t까지 구입했을때 남기지 않고 나눠줄 수 있는 경우는 (psum[t]-psum[h-1])%k==0인 경우다.
한번 만 주문할 수 있는 경우 가능한 주문방법 = 나머지가 같은 것들끼리 묶고, 각 묶음에서 두개를 뽑는 조합의 경우
0번부터 i번까지의 상자가 있고, 여러번 주문 할때 최대 주문 횟수를 maxBuys(i)라 할때
maxBuys(i) = max( maxBuys(i-1), maxBuys(j)+1) (이때 j는 psum[i]==psum[j]인 i보다 작은 최댓값)
#include<iostream> | |
#include<vector> | |
using namespace std; | |
// 문제 조건에 맞는 출력을 위한 MOD | |
const int MOD = 20091101; | |
int n, k; | |
// 각 상자에 담긴 인형의 수 | |
int box[100000]; | |
// 상자에 담긴 인형 갯수의 부분합을 k로 나눈 나머지 | |
int psum[100001]; | |
// psum 미리 구하기 | |
// 첫번째 상자부터 주문하는 경우를 고려하여 psum의 첫번째 원소 전에 0을 삽입 | |
void precalc() { | |
psum[0] = 0; | |
for (int i = 1; i <= n; i++) | |
psum[i] = (psum[i - 1] + box[i - 1]) % k; | |
} | |
// 한번 주문해서 구입할 수 있는 방법의 수 | |
int waysToBuy() { | |
int ret = 0; | |
vector<long long>count(k, 0); | |
// count[i] = psum[]이 i인 경우의 수 | |
for (int i = 0; i <= n; i++) | |
count[psum[i]]++; | |
// count[i]가 2이상이면 그 중 두개를 뽑는 조합을 더함 | |
for (int i = 0; i < k; i++) | |
if (count[i] >= 2) | |
ret = (ret + (count[i] * (count[i] - 1)) / 2) % MOD; | |
return ret; | |
} | |
// 겹치지 않고 몇 번이나 살 수 있는지 | |
int maxBuys() { | |
vector<int> ret(n + 1, 0); | |
// prev[i] = psum이 i였던 마지막 위치 | |
vector<int> prev(k, -1); | |
for (int i = 0; i <= n; i++) { | |
if (i == 0) | |
ret[i] = 0; | |
else | |
// i번째 상자를 고려하지 않는 경우 | |
ret[i] = ret[i - 1]; | |
// psum[i]와 같은 값이 이전에 발견 되었으면, | |
// 이전 발견 위치에서부터 지금 위치까지 주문한 경우 고려 | |
int loc = prev[psum[i]]; | |
if (loc != -1) | |
ret[i] = max(ret[i], ret[loc] + 1); | |
// prev에 현재 위치 기록 | |
prev[psum[i]] = i; | |
} | |
return ret.back(); | |
} | |
int main() { | |
int testcase; | |
cin >> testcase; | |
while (testcase--) { | |
cin >> n >> k; | |
for (int i = 0; i < n; i++) | |
cin >> box[i]; | |
precalc(); | |
cout << waysToBuy() << " " << maxBuys() << endl; | |
} | |
} |
코드 원본: https://github.com/sbl133/JongmanBook/blob/main/17.%20partial%20sum/CHRISTMAS.cpp
GitHub - sbl133/JongmanBook
Contribute to sbl133/JongmanBook development by creating an account on GitHub.
github.com

댓글을 통한 코드리뷰, 질문, 지적 언제든 환영입니다!
reference: 프로그래밍 대회에서 배우는 알고리즘 문제해결전략2
'Algorithm > algospot' 카테고리의 다른 글
algospot 짝이 맞지 않는 괄호(문제 ID: BRACKETS2) c++ (0) | 2021.09.28 |
---|---|
algospot 조세푸스 문제 (문제 ID: JOSEPHUS) c++ (0) | 2021.09.27 |
algospot 졸업 학기 (문제 ID: GRADUATION) c++ (0) | 2021.09.18 |
algospot 너드인가, 너드가 아닌가? (문제 ID: NERDS) c++ (0) | 2021.09.16 |
algospot 보물섬 (문제ID: TREASURE) c++ (0) | 2021.09.16 |