codevs 抄書問題系列

題目描述 Description

現在要把M本有順序的書分給K個人複製(抄寫),每一個人的抄寫速度都一樣,一本書不允許給兩個(或以上)的人抄寫,分給每一個人的書,必 須是連續的,比 如不能把第一、第三、第四本數給同一個人抄寫。現在請你設計一種方案,使得複製時間最短。複製時間爲抄寫頁數最多的人用去的時間。

輸入描述 Input Description

第一行兩個整數M、K;(K<=10000 M<=1000000 滿足 k<=m)
第二行M個整數,第i個整數表示第i本書的頁數。

輸出描述 Output Description

共K行,每行兩個正整數,第i行表示第i個人抄寫的書的起始編號和終止編號。K行的起始編號應該從小到大排列,如果有多解,則儘可能讓前面的人少抄寫。

樣例輸入 Sample Input

9 3
1 2 3 4 5 6 7 8 9

樣例輸出 Sample Output

1 5
6 7
8 9

codevs上的一系列題,題面一樣,數據範圍增加,然而最大數據範圍纔是本題的正解的複雜度O(mlog(sum)),sum爲二分的上界,不過跑100w還是有點虛233。感覺這題難在輸出上,打了一堆特判才過,二分的過程並不難,具體見代碼。
代碼如下

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int sz = 2000010;
int m,k;
int now;
ll num[sz];
struct gtnd
{
    int l,r;
}answers[sz];
int ans_len;
ll read()
{
    ll x = 0 , f = 1;
    char in = getchar();
    while(in < '0' || in > '9')
    {
        if(in == '-')
            f = -1;
        in = getchar();
    }
    while('0' <= in && in <= '9')
    {
        x = x * 10 + in - '0';
        in = getchar();
    }
    return x * f;
}
bool check(ll mid)
{
    now = 1;
    ll tot = 0;
    for(int i = 1 ; i <= m ; i ++)
    {
        while(tot + num[i] >= mid)
        {
            now ++;
            tot = 0;
            if(now > k)
                return false;
        }
        tot += num[i];
    }
    if(now > k)
        return false;
    return true;
}
int main()
{
    ll l = 0 , r = 0;
    m = read() , k = read();
    for(int i = 1 ; i <= m ; i ++)
        num[i] = read() , l = max(l,num[i]) , r += num[i];
    if(k == 1)
    {
        printf("1 %d\n",m);
        return 0;
    }
    while(r - l > 1)
    {
        ll mid = (l + r) / 2;
        if(!check(mid))
            l = mid;
        else
            r = mid;
    }
    int l_ans = 1;
    ll tot = 0;
    int red = k;
    int pos;
    int r_ans = m;
    for(pos = m ; pos >= 1 ; pos --)
    {

        if(tot + num[pos] > l)
        {
            red --;
            answers[++ ans_len].l = pos + 1 , answers[ans_len].r = r_ans;
            r_ans = pos;
            tot = 0;
        }
        tot += num[pos];
        if((red == pos+1 && tot) || (red == pos && !tot))
            break;
    }
    if(!pos)
        if(tot)
            answers[++ ans_len].l = 1 , answers[ans_len].r = r_ans;
    if(pos)
        if(tot)
            answers[++ ans_len].l = pos + 1 , answers[ans_len].r = r_ans;
    if(pos && red && (pos + 1 == red || pos == red))        
        for(int i = pos ; i >= 1 ; i --)
            answers[++ ans_len].l = i , answers[ans_len].r = i;
    for(int i = ans_len ; i >= 1 ; i --)
        printf("%d %d\n",answers[i].l,answers[i].r);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章