您的位置:首页 > 其它

BZOJ 1044 二分+DP

2013-03-12 23:30 239 查看
第一问,明显的二分答案+验证。

第二问,dp[i][j]表示前j段切i刀的满足第一问的方案数,然后dp[i][j]=sigma(dp[i-1][k]) (k满足第一问限制)

显然在循环j的时候是可以算出来这个值的,所以总复杂度是n*m的。

其实我一开始写的是dp[i][j]表示前i个切j刀的方案数,显然这样写不能优化。。。

然后写出方程,发现调换i、j就可以了~

View Code

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <algorithm>

#define N 55555
#define MOD 10007

using namespace std;

int n,m,a
,l,r,mid;
int sum
,ans,ans1;
int dp[2]
,q
;

inline void read()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
l=max(l,a[i]);
sum[i]=sum[i-1]+a[i];
}
}

inline bool check()
{
int gs=m,p=1,sm;
while(gs!=0&&p<=n)
{
sm=0;
while(p<=n&&sm+a[p]<=mid) sm+=a[p++];
gs--;
}
if(p<=n&&sum
-sum[p-1]>mid) return false;
return true;
}

inline void step1()
{
r=sum
;
while(l<=r)
{
mid=(l+r)>>1;
if(check()) ans=mid,r=mid-1;
else l=mid+1;
}
printf("%d ",ans);
}

inline void step2()
{
dp[0][0]=1;
for(int i=1;i<=m;i++)
{
int h=1,t=0,res;
q[++t]=0; res=dp[(i-1)&1][0];
for(int j=1;j<=n;j++)
{
while(h<=t&&sum[j]-sum[q[h]]>ans)
{
res-=dp[(i-1)&1][q[h]]; h++;
res%=MOD;
if(res<0) res+=MOD;
}
dp[i&1][j]=res;
q[++t]=j; res+=dp[(i-1)&1][j];
res%=MOD;
}
for(int j=n-1;j>=1;j--)
{
if(sum
-sum[j]>ans) break;
ans1+=dp[i&1][j];
ans1%=MOD;
}
memset(dp[(i-1)&1],0,sizeof dp[(i-1)&1]);
}
printf("%d\n",ans1);
}

inline void go()
{
step1();
step2();
}

int main()
{
read(),go();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: