2018년 6월 1일 금요일

15790 최종병기 활

15790 최종병기 활 https://www.acmicpc.net/problem/15790

고무줄이 주어진다. 고무줄의 둘레는 $n$이며 $m$개의 홈이 파져있다. 
고무줄을 잘라 $k$겹의 고무줄 중 가장 작은 고무줄의 길이를 최대화하는 문제이다.

순수 greedy만 생각을 했었는데 이분탐색으로 원의 기준을 돌리면서 $O(m^2 log n)$에 해결할 수 있다.

원의 기준을 돌리면서 arr배열에 다시 넣었는데 배열 크기를 2$m$으로 잡고 idx값만 바꾸면서 돌려줄 수 있다. 
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1005;
int n, m, k;
int arr[MAXN];
int sub[MAXN];
bool ispossible(int mid) {        // 모든 part >= mid인지 판별
    for (int i = 0; i < m; i++) {
        int t = 0;
        int idx = 0;
        for (int j = i; j < m; j++) arr[idx++= sub[j];
        for (int j = 0; j < i; j++) arr[idx++= sub[j];
        int here = 0;
        for (int j = 0; j < m; j++) {
            if (here < mid) here += arr[j];
            if (here >= mid) {
                here = 0;
                t++;
            }
        }
        if (here >= mid) t++;
        if (t >= k) return true;
    }
    return false;
}
int main() {
    scanf("%d%d%d"&n, &m, &k);
    for (int i = 0; i < m; i++scanf("%d"&arr[i]);
    for (int i = 0; i < m - 1; i++) sub[i] = arr[i + 1- arr[i]; sub[m - 1= n - arr[m - 1+ arr[0];
    int l = 1, r = n;
    while (l <= r) {
        int mid = (l + r) >> 1;
        if (ispossible(mid)) l = mid + 1;
        else r = mid - 1;
    }
    printf("%d\n", r);
    return 0;
}
cs

댓글 없음:

댓글 쓰기