[Algospot] 승률 올리기 (문제 ID : RATIO)
문제
싸비는 윈도우XP 운영체제에 포함되어 있는 스파이더 카드게임을 매우 좋아한다. 처음에는 지는 경우가 있었는데, 점점 연습을 함에 따라 필승법을 발견하였고 매번 승리를 하게 되었다.
스파이더 게임을 하면 플레이어에 대한 정보가 다음과 같이 주어지는데 싸비는 이것을 보다 표시되고 있는 승률을 1%이상 올리기 위해선 최소한 몇 번의 연승이 필요한지 의구심이 들었다.
플레이 횟수 : N
승리 횟수 : M(Z %)
여기서 Z%의 경우 소수점을 제외한 부분의 승률이다. 즉, 승률이 88.68% 일 경우 Z = 88% 이다.
N, M이 주어졌을 때, Z를 올리기 위한 최소한의 연승횟수가 필요한지 구하는 프로그램을 작성하라. 여기서 답이 되는 연승횟수는 2,000,000,000 이하라고 가정한다.
입력
입력의 첫번째 줄에는 테스트 케이스의 개수 T가 입력되고, 다음 줄 부터 한줄에 하나씩 T개의 테스트 케이스가 입력된다.
테스트케이스는 두 개의 숫자로 이루어진다. 처음에 들어오는 숫자는 스파이더를 플레이를 한 횟수N(1<=N<=1,000,000,000)를 의미하며, 나중에 들어온 숫자는 승리한 횟수M(0<=M<=N)를 의미한다.
출력
각 테스트 케이스에 대해서 한줄에 승률을 올릴 수 있을 경우 이를 위한 최소한의 연승 수를 출력하며, 불가능할 경우 -1을 출력한다.
의외의 뻘짓으로 시간을 소모한 문제이다.
승률을 구하기 위해서 이긴 횟수 / 전체 횟수로 구해야 하는데 N과 M을 헷갈려서 N / M을 해서 오답이 떴다.
또 decision 함수에서 origin+1 == new_num을 반환하게 했다가 왜 정답이 안 나올까 한참 고민을 했는데
새로운 비율이 기존 비율 + 1 보다 더 커질 수 있단 점을 간과했다. 즉 64퍼에서 66퍼로 증가하면 2퍼가 차이나는 건데 1퍼센트 차이에만 true를 반환하도록 해서 오답이 나왔다. 두가지 모두 고친 후 N과 M의 자료형도 long long으로 고치면 정답이 나온다.
코드 원본 : https://github.com/chosh95/STUDY/blob/master/Algospot/RATIO.cpp
chosh95/STUDY
알고리즘 문제풀이. Contribute to chosh95/STUDY development by creating an account on GitHub.
github.com
C++ 코드
#include <iostream>
#include <cmath>
using namespace std;
int T, origin;
long long N, M;
long long L = 2000000000;
bool decision(long long x)
{
int new_num = (100 * (M + x)) / (N + x);
return origin + 1 <= new_num;
}
int optimize()
{
origin = (100 * M) / N;
if (origin == (100 * (M + L) / (N + L))) return -1;
long long lo = 0, hi = L;
while (lo + 1 < hi) {
long long mid = (lo + hi) / 2;
if (decision(mid))
hi = mid;
else
lo = mid;
}
return hi;
}
int main()
{
cin >> T;
while (T--) {
cin >> N >> M;
cout << optimize() << endl;
}
}