列表

详情


NC19972. [HAOI2008]木棍分割

描述

有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处。
现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且输出有多少种砍的方法使得总长度最大的一段长度最小. 并将结果mod 10007。。。

输入描述

输入文件第一行有2个数n,m。
接下来n行每行一个正整数Li,表示第i根木棍的长度.n ≤ 50000,0 ≤ m ≤ min(n-1,10 00),1 ≤ Li ≤ 1000.

输出描述

输出有2个数, 第一个数是总长度最大的一段的长度最小值, 第二个数是有多少种砍的方法使得满足条件.

示例1

输入:

3 2                           
1 
1
10

输出:

10 2

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 664ms, 内存消耗: 1764K, 提交时间: 2020-03-27 18:03:47

#include<cstdio>
#include<algorithm>
#define N 50010
#define mod 10007
using namespace std;
int n,m,a[N],sl[N],f[2][N],sum[2][N];
bool judge(int mid)
{
	int i=0,now=0,cnt=0;
	for(i=1;i<=n;i++)
	{
		if(now+a[i]>mid) now=0,cnt++;
		now+=a[i];
	}
	return cnt<=m;
}
int main()
{
	int i,j,l=0,r=0,mid,ans=-1,p=0,ret=0,d;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)
	scanf("%d",&a[i]),l=max(l,a[i]),r+=a[i],sl[i]=sl[i-1]+a[i];
	while(l<=r)
	{
		mid=(l+r)>>1;
		if(judge(mid)) ans=mid,r=mid-1;
		else l=mid+1; 
	}
	printf("%d ",ans);
	for(i=0;i<=n;i++)
	sum[0][i]=1;
	for(i=d=1;i<=m+1;i++,d^=1)
	{
		sum[d][0]=p=0;
		for(j=1;j<=n;j++)
		{
			while(sl[j]-sl[p]>ans) p++;
			f[d][j]=sum[d^1][j-1];
			if(p) f[d][j]=(f[d][j]-sum[d^1][p-1]+mod)%mod;
			sum[d][j]=(sum[d][j-1]+f[d][j])%mod;
		}
		ret=(ret+f[d][n])%mod;
	}
	printf("%d\n",ret);
	return 0;
}

上一题