您的位置:首页 > 其它

BZOJ 1044 HAOI2008 木棍切割 二分答案+动态规划

2017-05-20 20:04 344 查看
题目大意:给定n个连在一起的木棍。分成m+1段。使每段最大值最小,求最大值的最小值及最大值最小时切割的方案数

第一问水爆了……二分答案妥妥秒过

第二问就有些难度了 首先我们令f[i][j]表示用前j个棒♂子得到i段的方案数

诶我没打什么奇怪的符号吧

于是我们有动规方程

f[i][j]=Σf[i-1][k] (sum[j]-sum[k]<=ans,k<j)

这个最坏情况下是O(m*n^2)的,肯定挂

我们发现k的下界是单调上升的 于是我们直接令k为当前j时k的下界。开一个变量记录k~j的f值之和

每次j++时将k向后调整 此外f数组要开滚动数组不然MLE

写完交上去各种神慢……搞不懂其它人都写了啥

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 50500
#define Mo 10007
using namespace std;
int n,m,limit,ans;
int maxlen=0,a[M],sum[M];
int f[2][M];
inline bool Judge(int x)
{
int i,re=0,now=x;
for(i=1;i<=n;i++)
{
if(now+a[i]>x)
++re,now=a[i];
else
now+=a[i];
if(re>m)
return false;
}
return true;
}
inline int Bisection()
{
int l=maxlen,r=sum
;
while(l+1<r)
{
int mid=l+r>>1;
if( Judge(mid) )
r=mid;
else
l=mid;
}
if( Judge(l) )
return l;
return r;
}
int main()
{
int i,j,k;
cin>>n>>m;++m;
for(i=1;i<=n;i++)
scanf("%d",&a[i]),sum[i]=sum[i-1]+a[i],maxlen=max(maxlen,a[i]);
limit=Bisection();
f[0][0]=1;
for(i=1;i<=m;i++)
{
int temp=0;k=i-2;
for(j=i;j<=n;j++)
{
temp+=f[~i&1][j-1],temp%=Mo;
while(sum[j]-sum[k+1]>limit)
temp+=Mo-f[~i&1][++k],temp%=Mo;
f[i&1][j]=temp;
}
ans+=f[i&1]
,ans%=Mo;
}
cout<<limit<<' '<<ans<<endl;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: