洛谷P1281 书的复制

版权声明:EL PSY CONGROO ! https://blog.csdn.net/THIS_IS_HPQ/article/details/81104059

题目背景

大多数人的错误原因:尽可能让前面的人少抄写,如果前几个人可以不写则不写,对应的人输出0 0。

不过,已经修改数据,保证每个人都有活可干。

题目描述

现在要把m本有顺序的书分给k给人复制(抄写),每一个人的抄写速度都一样,一本书不允许给两个(或以上)的人抄写,分给每一个人的书,必须是连续的,比如不能把第一、第三、第四本书给同一个人抄写。

现在请你设计一种方案,使得复制时间最短。复制时间为抄写页数最多的人用去的时间。

输入输出格式

输入格式:

第一行两个整数m,k;(k≤m≤500)

第二行m个整数,第i个整数表示第i本书的页数。

输出格式:

共k行,每行两个整数,第i行表示第i个人抄写的书的起始编号和终止编号。k行的起始编号应该从小到大排列,如果有多解,则尽可能让前面的人少抄写。

输入输出样例

输入样例#1:

9 3
1 2 3 4 5 6 7 8 9

输出样例#1:

1 5
6 7
8 9

这道题可以用DP解决,但是二分+贪心也是一种非常不错的解法。

我在这里谈一谈后者。

二分答案

       通常,当我们看到题目要求XXXXX的最大值最小是多少,又或者是XXXXXX的最小值最大是多少,这道题十有八九要用二分了。用二分发能在O(nlogn)的复杂度里枚举可能的答案,再写一个判断函数去判断二分出的值的大小。

       值得注意的是,运用二分法的时候,答案一定要满足单调性,不然无法二分。

        书的复制这道题,我们可以二分出每个人抄写的时间。然后从最后一个人开始枚举(题目中要求前面的人尽量抄写的少),用贪心的思想记录下每个人能够复制的书。如果所有书能够抄完,说明二分出的时间>=最小时间,如果不能,说明二分出的时间<=最小时间,就再次进行二分。

        二分最终得出的值就是正确答案了,从前往后输出即可。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int a[10001],k,m,sum=0,L[10001],R[10001];//ai表示编号为i的书的页数
bool check(int x)//二分判断答案正确性,这里我是在判断完正确答案之后再贪心求出答案。
{
	int s,tot=k,book=m;//book表示当前的书的标号
	s=x;//s表示当前的人剩余的时间
	while(tot&&book)
	{
		if(s>=a[book])
		{
			s-=a[book];
			book--;	
		}
		else
		{
			s=x;
			tot--;
		}
	}
	if(book==0)
		return 0;
	else
		return 1;
}
int main()
{
	cin>>m>>k;
	if(m==k&&m==0)
		return 0;
	for(int i=1;i<=m;i++)
	{
		cin>>a[i];
		sum+=a[i];
	}
	int l=sum/k,r=sum;
	while(l<r)//二分
	{
		int mid=(l+r)>>1;
		if(check(mid))
			l=mid+1;
		else
			r=mid;
	}
	int t=l,book=m;
	for(int i=k;i>=1;i--)
	{
		t=l;
		R[i]=book;
		while(t-a[book]>=0&&book>=1)
		{
			t-=a[book];
			book--;
		}
		L[i]=book+1;
	}
	for(int i=1;i<=k;i++)
		cout<<L[i]<<' '<<R[i]<<endl;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/THIS_IS_HPQ/article/details/81104059