【BZOJ1044】[HAOI2008]木棍分割(动态规划,贪心)

【BZOJ1044】[HAOI2008]木棍分割(动态规划,贪心)

题面

BZOJ
洛谷

题解

第一问随便二分一下就好了,贪心\(check\)正确性显然。
第二问随便前缀和+单调队列优化一下\(dp\)就完了。

#include<iostream>
#include<cstdio>
using namespace std;
#define MAX 50500
#define MOD 10007
void add(short int &x,short int y){x+=y;if(x>=MOD)x-=MOD;}
inline int read()
{
	int x=0;bool t=false;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return t?-x:x;
}
int n,m,a[MAX];
short int f[MAX][1010];
short int s[1010],ans;
bool check(int len)
{
	int ret=0,s=0;
	for(int i=1;i<=n;++i)
	{
		if(a[i]>len)return false;
		if(s+a[i]>len)++ret,s=0;
		s+=a[i];
	}
	if(s)++ret;return ret<=m+1;
}
int main()
{
	n=read();m=read();
	for(int i=1;i<=n;++i)a[i]=read();
	int l=1,r=5e7,ret=1e8;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(check(mid))ret=mid,r=mid-1;
		else l=mid+1;
	}
	printf("%d ",ret);
	for(int i=1;i<=n;++i)a[i]+=a[i-1];
	f[0][0]=s[0]=1;
	for(int i=1,l=0;i<=n;++i)
	{
		while(a[i]-a[l]>ret)
		{
			for(int j=0;j<=m+1;++j)add(s[j],MOD-f[l][j]);
			++l;
		}
		for(int j=m+1;j;--j)add(s[j],f[i][j]=s[j-1]);
	}
	for(int i=0;i<=m+1;++i)add(ans,f[n][i]);
	cout<<ans<<endl;
	return 0;
}
posted @ 2018-09-29 19:29  小蒟蒻yyb  阅读(372)  评论(0编辑  收藏  举报