1. 문제1
1072번: 게임
김형택은 지금 몰래 Spider Solitaire(스파이더 카드놀이)를 하고 있다. 형택이는 이 게임을 이길 때도 있었지만, 질 때도 있었다. 누군가의 시선이 느껴진 형택이는 게임을 중단하고 코딩을 하기 시
www.acmicpc.net
2. 풀이1
탐색범위는 x+1부터 충분히 큰 수까지..
x가 제한이 10의 9제곱인데.. 이는 입력으로 주어지는 x가 10의 9제곱이지 가능한 제한이 10의 9제곱이라는 뜻은 아니다.
그래서 대충 10의 18제곱까지 탐색하도록 범위를 잡았다
그리고 절대로 지지 않는다고 했기 때문에... x 기준으로 현재 x+k를 잡았다면...
y값은 y+k로 바뀌겠지
그리고 그때 변화된 승률도 (y+k)*100//(x+k)
문제에서 요구하는건 승률이 변하냐 안변하냐이다.
그러니까 새롭게 계산한 승률 (y+k)*100//(x+k)와 원래 승률 y*100//x가 서로 다른지 같은지를 체크한다.
서로 다르다면?
문제에서 요구하는건 승률이 변하는 "최소 판수"이므로.. end = mid로 옮겨서 더 작은 판수가 가능한지 체크
서로 같다면?
현재 정한 판수보다 큰 판수를 탐색해야할테니, start = mid + 1로 옮긴다
from sys import stdin
def binary_search(target,start,end,x,y):
while start < end:
mid = start + (end-start)//2
new_y = y + mid-x
new_z = new_y*100//mid
if new_z != target:
end = mid
else:
start = mid + 1
return end
MAX = 10**18
x,y = map(int,stdin.readline().split())
z = y*100//x
answer = binary_search(z,x+1,MAX+1,x,y)
if answer > MAX:
print(-1)
else:
print(answer - x)
탐색한 결과가.. 최대 범위로 지정한 값보다 크게 나온다면.. 아무리 해도 승률이 변하지 않는다는 의미니까 -1을 출력했고
그 이외의 경우는 나온 결과 - 원래 판수를 하면 최소 해야하는 판수가 되겠지
3. 풀이2
근데 그냥 일차부등식으로도 풀린다고 한다
앞으로 게임에서 반드시 승리하므로, 승률은 무조건 증가할것이다.
이때, Z가 정수이므로, Z가 최소로 변한다면...
Z가 1 증가하는 것이고 최소 k판 더 한다고 하면, 그 승률은 100y+100kx+k
원래 승률은 z=100yx
따라서 다음 부등식을 만족해야한다.
100y+100kx+k>=z+1
부등식을 정리하면... 100y+100k>=x(z+1)+k(z+1) 여기서 이항해서 더 정리하면...
100y−x(z+1)>=k(z−99)
이 부등식에서 z = 99이면 성립하지 않으므로, z가 변하지 않는 경우이고
z = 100이면, 100y−100x>=k인데, 좌변이 음수이므로 k가 음수가 되니 성립하는 식이 아니다.
그래서 z >= 99이면 몇판을 해도 변하지 않는다
반대로 z < 99이면, z-99로 부등식의 양변을 나눠서...
(100y−x(z+1))(z−99)<=k
따라서 좌변의 식을 계산해서 최소 정수 k를 구해주면 되겠다
from sys import stdin
x,y = map(int,stdin.readline().split())
z = 100*y//x
if z >= 99:
print(-1)
else:
k = (100*y-x*(z+1))/(z-99)
if k == int(k):
print(int(k))
else:
print(int(k)+1)
4. 문제2
7795번: 먹을 것인가 먹힐 것인가 (acmicpc.net)
7795번: 먹을 것인가 먹힐 것인가
심해에는 두 종류의 생명체 A와 B가 존재한다. A는 B를 먹는다. A는 자기보다 크기가 작은 먹이만 먹을 수 있다. 예를 들어, A의 크기가 {8, 1, 7, 3, 1}이고, B의 크기가 {3, 6, 1}인 경우에 A가 B를 먹을
www.acmicpc.net
5. 풀이
핵심은 (A,B) 쌍의 개수를 셀건데, A > B인 쌍의 개수만 셀것이다
A,B 배열을 정렬하고, A를 target으로 잡은 다음에 B 배열에서 B[mid]가 target보다 크거나 같다면??
mid이후는 target보다 모두 크거나 같다.. 그러니까 볼 필요가 없으므로 end = mid로 옮겨준다. 왜냐하면 B < A인 쌍을 구해야하니까...
이러한 지점은 mid보다 작은 지점에 있을 것이다
반대로 B[mid] < target이라면? mid이후는 조건을 만족하는 부분이다.. 그러면 start = mid + 1???
근데 mid도 조건을 만족할 수 있는데...?
from sys import stdin
def binary_search(array,target,start,end):
while start < end:
mid = start + (end - start)//2
if array[mid] > target:
end = mid
else:
start = mid + 1
return end
T = int(stdin.readline())
for _ in range(T):
n,m = map(int,stdin.readline().split())
A = list(map(int,stdin.readline().split()))
B = list(map(int,stdin.readline().split()))
A.sort()
B.sort()
count = 0
for i in range(m):
j = binary_search(A,B[i],0,n)
if j == n:
j -= 1
break
count += (n-(j+1)+1)
print(count)
이렇게 생각이 꼬이더니.. 반대로 B를 target으로 잡은 다음에 A배열에서 이분탐색을 해보자는 생각에 이르렀다
A배열에서 target = B[i]보다 큰 지점을 이분탐색으로 찾는다면...
A[mid] > target이라면.. mid 이후는 조건을 만족하는 부분이므로.. end = mid로 해서 mid 보다 작은 쪽을 탐색해야 할 것이다.
반대로 A[mid] <= target이면... mid 이전은 모두 target보다 작으니 start = mid + 1로 해서 mid보다 큰 쪽을 탐색해야 한다.
이렇게 하면 A를 target으로 잡아 B 배열에서 이분탐색할때 꼬이던 로직이 명확해진다..
이분 탐색한 결과 end를 return하고 그 지점이 j라면.. j 이후는 모두 A > B인 지점이다
따라서, A배열의 개수 - (j+1) + 1을 해서 j부터 A배열 끝까지 개수를 세주면.. B가 고정되어 있을때, A > B인 쌍을 셀 수 있다.
A > B를 만족하는 값이 A배열에 존재하지 않아 j = n이 된다면... 반복문을 탈출해준다.
현재 B[i]에서 A > B인 쌍을 찾지 못했다면.. 모든 A의 원소에 대해 B[i]보다 작다는 뜻이고.. 현재 A,B가 정렬되어 있으므로
B[i]보다 큰 B[i+1]도 당연히 모든 A의 원소보다 크므로, 그 이후는 A > B인 쌍이 존재하지 않는다
'알고리즘 > 이분 탐색' 카테고리의 다른 글
[Java]자바로 이진탐색 연습2 -올바르게 사고하기- (0) | 2023.04.02 |
---|---|
[Java]자바로 이분탐색 연습 -기본, lower bound, upper bound- (0) | 2023.04.01 |
처음 배우는 parametric search 이해해보기 (0) | 2023.03.29 |
이분탐색의 올바른 사고방식 익히고 lower_bound, upper_bound 가볍게 복기하기 (0) | 2023.03.29 |
이분탐색 응용력 키우기 연습1 -차이가 가장 가까운 값을 찾는 방법- (0) | 2023.03.28 |