https://www.acmicpc.net/problem/1561
1561번: 놀이 공원
첫째 줄에 N(1 ≤ N ≤ 2,000,000,000)과 M(1 ≤ M ≤ 10,000)이 빈칸을 사이에 두고 주어진다. 둘째 줄에는 각 놀이기구의 운행 시간을 나타내는 M개의 자연수가 순서대로 주어진다. 운행 시간은 1 이상 30
www.acmicpc.net
접근 방법
처음엔,
문제에서 구하라는 것을 직접적으로 n번째 아이가 몇 번째 놀이기구를 타게 될 지를 고민했었다.
필연적인 사고였지만, 직접 손으로 시행을 해보면서 얻은 결과는 모든 운행 시간들의 배수마다 매번 몇 명의 아이들이 타는 지, 총 몇 명의 아이들이 탔는지를 생각해주어야 하는데,
이는
1. n번째 아이가 탈 때가 언제인지 미리 알 수 없다는 점,
2. 모든 운행 시간들의 배수만 확인하는게 쉽지 않다는 점
때문에 다른 방법을 생각해보기로 했다.
그 다음엔,
시간을 기준으로 생각을 해 보았다.
어느 정도의 시간이 있어야 n번째 아이도 놀이기구를 탈 수 있을까? 라는 생각을 했고,
여기서 총 시간을 기준으로 이분 탐색을 하면 풀 수 있지 않을까? 라는 생각으로 풀었다.
풀이
총 시간을 기준으로 이분 탐색을 하자.
\(총 시간 동안 탈수 있는 놀이 기구의 횟수 = cnt\) 라 하자.
\(cnt \geq n\) 일때에는 총 시간을 작게
\(cnt<n\) 일때에는 총 시간을 크게 하는 이분 탐색을 하자.
이때,\( cnt=((총 시간)/a[i])+1 (1 \leq i \leq m)\) 이다.
이러면 최종적으로 이분 탐색의 결과로서 ans에는 n명의 아이들이 모두 놀이기구를 탈 수 있는 시간의 최솟값이 저장된다.
이제 n번째 아이가 탈 놀이기구의 번호를 구해보자.
\(ans%a[i]==0\) 는 ans분째에 i번 놀이기구를 탈 수 있다는 뜻이므로, 이런 i를 nums 배열에 저장해두자.
\(cnt == (ans-1)분까지 탄 놀이기구의 수\) 라 하면
\(n-cnt\)는 ans분째 탈 놀이기구의 수가 되므로
정답은 nums[(n-cnt)-1] 이다.
시간 복잡도
\(O(m*lg(r-l))\)
l의 가능한 최소는 1
r가 가능한 최대는 \(30*20억=600억=6*1e11\)
이므로 최악의 경우에 대략 \(10000*39\)번의 연산을 하므로 충분히 시간 안에 가능하다.
코드
#include <bits/stdc++.h>
#define ll long long int
#define pll pair<ll, ll>
#define pii pair<int, int>
#define X first
#define Y second
using namespace std;
int dx[]={-1, 1, 0, 0};
int dy[]={0, 0, -1, 1};
void solve()
{
ll n, m; cin>>n>>m;
ll a[m+1], l=0, r=n, mx=1, ans;
for(int i=1;i<=m;i++)
{
cin>>a[i];
if(a[i]>mx) mx=a[i];
}
r*=mx;
if(n<=m) //0분만에 마지막 아이가 놀이기구를 타는 경우 처리
{
cout<<n<<'\n';
return ;
}
while(l<=r)
{
ll mid=(l+r)/2;
ll cnt=m; //0분에 탄 학생 뒤에서 포함 안되므로 여기서 처리
for(int i=1;i<=m;i++) cnt+=(mid/a[i]);
if(cnt>=n)
{
r=mid-1;
ans=mid; //최종적으로 ans에는 n명의 아이들이 모두 놀이기구를 탈 수 있는 시간의 최솟값이 저장된다.
}
else l=mid+1;
}
vector<int> nums;
ll cnt=m;
for(int i=1;i<=m;i++)
{
cnt+=ans/a[i];
if(ans%a[i]==0)
{
cnt--;
nums.push_back(i); //ans분째에 탈 수 있는 놀이기구의 번호 저장
}
}
cout<<nums[(n-cnt)-1]<<'\n'; //cnt에는 (ans-1)분째까지 아이들이 탄 놀이기구 수, 결국 n-cnt는 ans분째 탈 놀이기구 수
}
int main()
{
ios::sync_with_stdio(0); cin.tie(0);
int tc=1;
while(tc--) solve();
return 0;
}
'PS' 카테고리의 다른 글
PS 환경 설정 글 모음 (0) | 2022.07.23 |
---|---|
[BOJ] 2785번: 체인 (0) | 2022.06.23 |
[BOJ] 5525번: IOIOI (0) | 2022.06.15 |
[BOJ] 1966: 프린터 큐 (0) | 2022.06.12 |
[BOJ] 2981: 검문 (1) | 2022.06.08 |