UVa 714 & POJ 1505 & ZOJ 2002 - Copying Books

传送门 ::UVa:UVa 714 & POJ 1505 & ZOJ 2002 - Copying Books

→→→ ::ZOJ:UVa 714 & POJ 1505 & ZOJ 2002 - Copying Books


题意:按给出的组数划分输入的数,使一组中的最大值最小。

全程参考了shuangde800的解题报告。


就是用二分定一个值,然后根据以此划分的组数缩小范围。。

有点理解不能,明天再想想。


#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 600;

long long k, m, minNum, sum, ans, num[MAXN];
int vis[MAXN];

inline long long BinSearch();
inline int Devide(long long mid);
inline void Output();

int main()
{
    //freopen("input.txt", "r", stdin);
    int T, i, j;
    scanf("%d", &T);
    while (T--)
    {
        scanf("%d%lld", &m, &k);
        for (i = 0; i < m; i++)
        {
            scanf("%d", &num[i]);
            minNum = min(minNum, num[i]);
            sum += num[i];
        }
        ans = BinSearch();
        Output();
    }
    return 0;
}

inline long long BinSearch()
{
    long long left = minNum, right = sum, mid;
    while (left < right)
    {
        mid = left + (right - left) / 2;
        if (Devide(mid) <= k)
            right = mid;
        else
            left = mid + 1;
    }
    return right;
}

inline int Devide(long long target)
{
    memset(vis, 0, sizeof(vis));
    int cnt = 0, pos = m - 1;
    while (pos >= 0)
    {
        long long sum = 0;
        bool ok = true;
        while (pos >= 0 && sum + num[pos] <= target)
        {
            ok = false;
            sum += num[pos--];
        }
        if (ok)
            return k + 1;
        if (pos >= 0)
            vis[pos] = 1;
        cnt++;
    }
    return cnt;
}

inline void Output()
{
    int cnt = Devide(ans);
    for (int i = 0; i < m - 1 && cnt < k; i++)
        if (!vis[i])
        {
            vis[i] = 1;
            cnt++;
        }
    for (int i = 0; i < m; i++)
    {
        if (i)
            printf(" %lld", num[i]);
        else
            printf("%lld", num[i]);
        if (vis[i])
            printf(" /");
    }
    printf("\n");
}


你可能感兴趣的:(ACM,ZOJ,poj,uva)