[문제]
김형택은 지금 몰래 Spider Solitaire(스파이더 카드놀이)를 하고 있다. 형택이는 이 게임을 이길 때도 있었지만, 질 때도 있었다. 누군가의 시선이 느껴진 형택이는 게임을 중단하고 코딩을 하기 시작했다. 의심을 피했다고 생각한 형택이는 다시 게임을 켰다. 그 때 형택이는 잠시 코딩을 하는 사이에 자신의 게임 실력이 눈에 띄게 향상된 것을 알았다.
이제 형택이는 앞으로의 모든 게임에서 지지 않는다. 하지만, 형택이는 게임 기록을 삭제 할 수 없기 때문에, 자신의 못하던 예전 기록이 현재 자신의 엄청난 실력을 증명하지 못한다고 생각했다.
게임 기록은 다음과 같이 생겼다.
- 게임 횟수 : X
- 이긴 게임 : Y (Z%)
- Z는 형택이의 승률이고, 소수점은 버린다. 예를 들어, X=53, Y=47이라면, Z=88이다.
X와 Y가 주어졌을 때, 형택이가 게임을 최소 몇 번 더 해야 Z가 변하는지 구하는 프로그램을 작성하시오.
[입력]
각 줄에 정수 X와 Y가 주어진다.
[출력]
첫째 줄에 형택이가 게임을 최소 몇 판 더 해야하는지 출력한다. 만약 Z가 절대 변하지 않는다면 -1을 출력한다.
[제한사항]
1 ≤ X ≤ 1,000,000,000
0 ≤ Y ≤ X
[예제]
>문제 풀이
>문제 이해
게임횟수: X
이긴 게임: Y(Z%)
Z는 형택이의 승률, 소수점은 버린다.
ex) X=53, Y=47 → Z =47/53*100=88.xx → 88
input))
X(10억이하), Y
output))
형택이가 최소 몇판을 더 해야하는지 출력
단, 만약 Z가 절대 변하지 않는다면 -1 출력
>문제 풀이
절대 Z가 변하지 않는 경우는??
1) 일단, Z가 100이면 101%로 올라갈 수 없다.
2) Z가 99이면? 이미 전적에 패배가 있기 때문에 몇경기를 더 이기든 100%로 올라갈 수 없다.
위의 경우를 제외하고는 탐색을 하면되는데
우리가 구하려고 하는 값을 answer라고 할때 answer=1~X까지의 수이다.
- 왜?)) 최소 한 경기 이상은 해야 승률이 오를것이고
Z가 98%의 경우 (98+100)/200*100=99퍼로 확률이 올라가기 때문이다.
이제 어떤 방법으로 탐색을 할지 정해야한다.
1~X까지 탐색을 하려면 최악의 경우 10억번을 탐색해야한다. (시간복잡도 O(N))
그러나 이분탐색을 하게 된다면 O(logN) 만에 탐색이 가능하다.
여기까지 왔다면 이분탐색을 구현하면되는데
나는 1) while의 조건문과 (left<=right) (left<right)
2) left=mid+1;, right= mid-1인가 mid로 해야되나 여기서 헷갈렸다..
이전에 이분탐색 할 때도 헷갈렸었는데, 왜 그렇게 되는지 확실히 인지하지 못한채 넘겼어서 그런 것 같다.
1)번의 경우 Z=98일 때는 위에 설명했던 것 처럼 left를 쭉쭉 올려서 right까지 가야하는데 mid=(left+right)/2로 계산하기 때문에 mid에 right값도 들어가려면 left==right일 때도 고려를 해야하기 때문이다.
그래서 left<=right 여야 한다. (코드에 따라 다를 수 있음)
2)번의 경우
초기값 설정할 때도 left=1, right=X로 mid로 올수 있는 값들의 범위를 설정해준거나 다름 없기 때문에 while안에서 left, right 값을 조정할 때도 mid가 올 수 있는 값만 고려해주면 된다.
mid로 계산했을 때 확률이 Z보다 높으면 다음에 고려할 값은 mid 아래의 값들만 고려해주면 되기 때문에 right=mid-1로 조정해주면 된다.
>전체 코드
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.io.IOException;
public class Main {
public static void main(String [] args) throws IOException {
BufferedReader br= new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st= new StringTokenizer(br.readLine());
long answer=-1;
long X= Long.parseLong(st.nextToken());
long Y= Long.parseLong(st.nextToken());
int Z= (int)(Y*100/X);
//Z==100: 100퍼에서 101퍼로 못올림
//Z==99: 전적에 이미 패가 있기 때문에 어떤 방법을 써도 100퍼는 못만든다.
//이분탐색 logN
long left=1, right=X, mid=0;
int nZ;
while(left<=right) {
if(Z>=99) {
answer=-1;
break;
}
mid= (left+right)/2;
nZ= (int)((Y+mid)*100/(X+mid));
if(nZ<=Z) {
left=mid+1;
}else {
answer= mid;
right=mid-1;
}
}
System.out.println(answer);
}//main
}
'알고리즘 > 백준 알고리즘' 카테고리의 다른 글
[백준 알고리즘]2143번: 두 배열의 합_Java (0) | 2021.10.03 |
---|---|
[백준 알고리즘]2243번: 사탕상자_Java (0) | 2021.10.03 |
[백준 알고리즘]1713번: 후보 추천하기_Java (0) | 2021.09.30 |
[백준 알고리즘]7579번: 앱_Java (0) | 2021.09.30 |
[백준 알고리즘]2449번: 전구_Java (0) | 2021.09.30 |