컴공과컴맹효묘의블로그

백준 알고리즘[16112]-5차 전직 본문

알고리즘/백준

백준 알고리즘[16112]-5차 전직

효묘 2020. 6. 21. 16:57
반응형

문제 사이트 : https://www.acmicpc.net/problem/16112

 

문제

메이플스토리 뉴비 키파가 드디어 레벨 200을 달성하고 5차 전직이라는 시스템을 이용해 캐릭터를 더욱 강력하게 만들려고 합니다. 5차 전직을 하려면 먼저 퀘스트를 통해 아케인스톤이라는 아이템을 받아야 합니다. 아케인스톤을 활성화시키면 캐릭터가 얻는 경험치를 아케인스톤에 모을 수 있습니다. 5차 전직을 하기 위해서는 총 n개의 퀘스트를 진행해서 n개의 아케인스톤을 받아야 하며, 각각의 아케인스톤에 5억 이상의 경험치를 모으면 5차 전직을 진행할 수 있는 자격이 주어집니다.

i번째 퀘스트를 진행하면 ai의 경험치와 i번째 아케인스톤이 주어집니다. 퀘스트로 얻는 경험치도 사냥으로 얻는 것과 똑같은 경험치이기 때문에, i번째 퀘스트의 보상 경험치를 받을 때 활성화되어 있던 아케인스톤에는 ai의 경험치가 추가됩니다.


메이플월드의 아케인스톤입니다. 멋지죠.

원래 메이플스토리에서는 한 번에 하나의 아케인스톤만 활성화시켜 놓을 수 있고, 각각의 아케인스톤에는 최대 5억의 경험치를 채울 수 있습니다. 그러나 해킹에는 자신이 있었던 메린이 키파는 서버를 해킹해 아케인스톤의 최대 경험치 제한을 없애 버리고, 최대 k개의 아케인스톤이 동시에 활성화되어 있을 수 있도록 바꿨습니다. 따라서 한 퀘스트의 보상 경험치가 여러 개의 아케인스톤에 추가될 수 있습니다. 예를 들어 1번째와 3번째 아케인스톤이 활성화되어 있는 상태에서 2번째 퀘스트를 진행해 100,000의 경험치와 2번째 아케인스톤을 획득하면, 1번째와 3번째 아케인스톤에 각각 100,000의 경험치가 추가되고 2번째 아케인스톤은 모인 경험치가 0인 상태로 받게 됩니다.

키파는 퀘스트를 원하는 순서대로 진행할 수 있지만, 같은 퀘스트를 두 번 이상 진행할 수는 없습니다. 키파는 퀘스트를 진행하면서 아케인스톤을 적절히 활성화 또는 비활성화시켜서 아케인스톤에 모인 경험치의 합을 최대화하고 싶습니다. 모인 경험치의 합이 커지면 어쨌든 기분이 좋으니까요. 키파를 대신해서 이 값을 구해 주세요!

 

입력

첫째 줄에 정수 n과 k(1 ≤ k  n ≤ 3 · \(10^5\))가 주어집니다.

둘째 줄에 n개의 정수가 공백을 사이에 두고 주어집니다. i번째 정수는\(a_i\)이며 0보다 크고 \(10^8\)보다 작거나 같습니다.

 

출력

첫째 줄에 키파가 아케인스톤에 모을 수 있는 경험치의 합의 최댓값을 출력합니다.

 

풀이 과정

일단 예제 입력으로 어떻게하면 최대값을 구할 수 있는지 나열해봤습니다.

 

1: 0 - - : 100*0  (sum = 0)
2: 200 - 0 : 200*1 (sum = 200)
3: 500 0 300 : 300*2 (sum = 800)

 

패턴이 보이시나요?

 

100*0

200*1

300*2 이 수식을 보고 패턴을 찾았습니다.

 

일단 입력의 순서와는 상관없이 100, 200, 300 이렇게 오름차순으로 작동하는 것을 볼 수있습니다. 왼쪽의 피연산자도 마찬가지입니다.

피연산자는 0부터 k까지만의 값을 갖습니다.

여기서 100, 200, 300이렇게 오름차순으로 정렬했는데 무조건 오름차순이 아닐 수도 있습니다. 직관으로도 오름차순인 것을 눈치챌 수도 있지만, 그래도 한번 증명해봤습니다.

 

경험치를 의미하는 정수 a와 b, 위 식에서 오른쪽 피연산자와 k를 표현하는 n, k에 대해서 생각해봅니다.

 

\[\hbox{let } a, b, n, k \in N\cup0\]
\[\hbox{let }a < b\]
\[\hbox{let }b = a + q \hbox{ s.t. } q \in N\]
\[\hbox{proof }an+b(n+1) > bn+a(n+1)\]
\[b>a\]

 

대충해봤지만, 오름차순이 아닌 경우는 없는 것을 볼 수 있습니다.

이제 이 논리를 코드로 작성하면 됩니다.

github: https://github.com/daily-boj/yoonki1207/blob/master/P16112.cpp

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

int main() {
	int n, k;
	vector<int> v;
	scanf("%d %d", &n, &k);
	for (int i = 0; i < n; i++) {
		int tmp;
		scanf("%d", &tmp);
		v.push_back(tmp);
	}
	int i = 0;
	long long int sum = 0LL;
	sort(v.begin(), v.end());
	for (int j = 0; j < n; j++) {
		sum += (long long int)v.at(j) * (long long int)i;
		if (i < k)
			i++;
	}
	printf("%lld\n", sum);
}

 

 

주의할 점

이 간단한 문제를 푸는데 필자를 1시간 동안이나 애먹게 한 것이 있습니다. 바로 메모리 문제인데요, sum에게만 long long int를 적용해주면 작동할 줄 알았습니다. 그런데 sum을 계산하는 과정에서 v.at(j) * i가 /(3*10^5*10*8/)까지 값을 가질 수 있다는 사실을 간과했습니다..

반응형
Comments