UVA714- Copying Books(最大最小化)

意甲冠军:k手稿的部分成m部分,使每一个和最小


思路:典型最大值最小化问题,使用贪心+二分。

贪心的是每次尽量将元素往右边划分,二分查找最小的x满足m个连续的子序列和S(i)都不超过x。

由于输出的原因。在划分时就从后往前尽量划分。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long ll;
const int MAXN = 1005;

int m, k, t;
int arr[MAXN], vis[MAXN];
ll ans, sum, Min;

int judge(ll x) {
    memset(vis, 0, sizeof(vis));
    ll s = 0;
    t = 0;
    int flag = 1;
    for (int i = m - 1; i >= 0; i--) {
        if (arr[i] > x) {
            flag = 0; 
            break;
        } 
        if (s + arr[i] > x) {
            vis[i] = 1;
            t++;
            s = arr[i];
            if (t > k - 1) {
                flag = 0; 
                break;
            }  
        }
        else  
            s += arr[i];   
    }    
    return flag;
}

int binary() {
    ll x = Min, y = sum;
    while (x < y) {
        ll mid = x + (y - x) / 2;
        if (judge(mid)) 
            y = mid;
        else
            x = mid + 1; 
    }
    return x;
}

void outPut() {
    judge(ans);
    int num = k - 1 - t;
    for (int i = 0; i < m; i++) {
        if (vis[i] == 0 && num) {
            vis[i] = 1; 
            num--; 
        }
    } 
    for (int i = 0; i < m - 1; i++) {
        printf("%d ", arr[i]);
        if (vis[i])
             printf("/ "); 
    } 
    printf("%d
", arr[m - 1]);
}

int main() {
    int cas;
    scanf("%d", &cas);
    while (cas--) {
        scanf("%d %d", &m, &k);         
        ans = 0;
        Min = arr[0];
        for (int i = 0; i < m; i++) {
            scanf("%d", &arr[i]); 
            sum += arr[i]; 
            if (Min < arr[i])
                Min = arr[i];
        }

        ans = binary();
        outPut();
    }  
    return 0;
}


版权声明:本文博客原创文章,博客,未经同意,不得转载。

原文地址:https://www.cnblogs.com/blfshiye/p/4676224.html