題目描述 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;
}