Skip to content

14163: 【原4163】矮人的宝藏

题目

题目描述

author: Yifan 原OJ链接:https://acm.sjtu.edu.cn/OnlineJudge-old/problem/4163

题目描述

矮人终于找到了他们失落的宝藏!现在有n个宝箱并排放在一起,第i个宝箱有\(a_i\)块黄金。m\(m \le n\)个矮人在讨论如何瓜分这些宝箱。规定每个矮人只能选择连在一起的若干个宝箱,每个宝箱都被一个矮人所拥有,每个矮人得到的黄金块数为他选择的所有宝箱的黄金块数之和。求获得黄金最多的矮人得到的黄金块数的最小值。

输入格式

第一行包含两个正整数n, m。

第二行包含n个用空格隔开的非负整数\(a_i\)(\(1 \le i \le n\)),保证\(a_i\)不全为0。

输出格式

一个正整数,表示获得黄金最多的矮人得到的黄金块数的最小值。

样例输入

5 3
4 2 4 5 1

样例输出

6

样例说明

第1个矮人选择第1个宝箱,得到4块黄金;第2个矮人选择第2,3个宝箱,得到6块黄金;第3个矮人选择第4,5个宝箱,得到6块黄金。获得黄金最多的矮人得到6块黄金。

数据范围

对20%的数据,\(n \le 10\)。

对50%的数据,\(n \le 1000\)。

对于100%的数据,\(n \le 100000, m \le n\),\(a_i\)之和不超过\(10^9\)。

ligongzzz's solution

#include "iostream"
#include "cstdio"
#include "cstring"
using namespace std;

int val_data[100009] = { 0 };

int main() {
    int n, m;
    scanf("%d %d", &n, &m);

    int left = 0, right = 0;

    for (int i = 0; i < n; ++i) {
        scanf("%d", &val_data[i]);
        right += val_data[i];
        left = val_data[i] > left ? val_data[i] : left;
    }

    int right_ans = 0;

    while (left <= right) {
        auto mid = (left + right) >> 1;
        int cnt = 0;
        for (int i = 0; i < n; ) {
            int cur_ans = 0;
            ++cnt;
            for (int j = i;; ++j) {
                cur_ans += val_data[j];
                if (cur_ans > mid) {
                    i = j;
                    break;
                }
                if (j == n - 1) {
                    i = j + 1;
                    break;
                }
            }
        }
        if (cnt <= m) {
            right_ans = mid;
            right = mid - 1;
        }
        else {
            left = mid + 1;
        }
    }

    cout << right_ans;

    return 0;
}

WashSwang's solution

#include <iostream>
#include <cstdio>
using namespace std;
int n,m,a[100001],l,r,mid,ans,cnt,cur;
bool flag;
int main() {
    scanf("%d%d",&n,&m);
    for (int i=0;i<n;++i)
        scanf("%d",&a[i]);
    l=0;
    r=1000000000;
    while (l<=r){
        mid=(l+r)/2;
        cnt=0;
        cur=0;
        flag=true;
        for (int i=0;i<n;++i){
            if (a[i]>mid){
                flag=false;
                break;
            }
            if (cur+a[i]>mid){
                cur=0;
                cnt++;
            }
            if (cnt==m){
                flag=false;
                break;
            }
            cur+=a[i];
        }
        if (flag){
            ans=mid;
            r=mid-1;
        }
        else l=mid+1;
    }
    printf("%d",ans);
    return 0;
}

yyong119's solution

#include <cstdio>
#define MAX_N 100010
#define max(x, y) ((x) > (y) ? (x) : (y))
using namespace std;
int n, m;
bool flag;
int a[MAX_N];
inline int read() {
    char ch = getchar(); int res = 0;
    while (ch < '0' || ch > '9') ch = getchar();
    while (ch >= '0' && ch <= '9')
        res = (res << 3) + (res << 1) + (ch ^ 48), ch = getchar();
    return res;
}
int main() {
    n = read(), m = read();
    int l = 0, r = (int)1e9 + 5;
    for (register int i = 0; i < n; ++i) {
        a[i] = read();
        l = max(l, a[i]);
    }
    while (l < r) {
        int mid = (l + r) >> 1;
        flag = true;
        int cnt = 1, cur_sum = 0;
        for (register int i = 0; i < n; ++i)
            if (cur_sum + a[i] > mid) {
                cur_sum = a[i];
                ++cnt;
                if (cnt > m) {
                    flag = false; break;
                }
            }
            else cur_sum += a[i];
        if (flag) r = mid;
        else l = mid + 1;
    }
    printf("%d", l);
    return 0;
}