传送门
http://www.lydsy.com/JudgeOnline/problem.php?id=1044
题目大意
给定n段木棍,最多切m刀,并使最大段最小
1.询问最大段
2.询问方案数
题解
dp[i,j]:表示前i段切j刀的方案数
显然
dp[i,j]=∑sum[i]−sum[k]<=ans1dp[k,j−1]
这是个
O(N2M)
的
这个是一段的转移,所以我们考虑用前缀和优化
并不好看是吧,我们稍微调整一下
dp[i,j]:表示前j段切i刀的方案数
dp[i,j]=∑sum[j]−sum[k]<=ansdp[i−1,k]
这样前缀和就显然了吧~
然后我们发现sum[k]是单调增的,所以~
最后注意空间上的问题,第一维滚动一下
uses math;
const
maxn=50001;
var
x,sum,s:array[-1..maxn]of longint;
f:array[0..1,-1..maxn]of longint;
i,j,k:longint;
n,m,l,r,mid,ans,a,b,tt,t:longint;
function check(a:longint):longint;
var i,tt,tot:longint;
begin
tt:=0; tot:=0;
for i:=1 to n do
if tt+x[i]>a
then begin inc(tot); tt:=x[i]; end
else inc(tt,x[i]);
inc(tot);
if tot>m+1 then exit(0) else exit(1);
end;
begin
readln(n,m); sum[0]:=0; l:=0;
for i:=1 to n do
begin readln(x[i]); sum[i]:=sum[i-1]+x[i]; l:=max(l,x[i]); end;
l:=0; r:=sum[n]; ans:=l;
while l<=r do
begin
mid:=(l+r)>>1;
if check(mid)=1
then begin ans:=mid; r:=mid-1; end
else l:=mid+1;
end;
write(ans,' ');
f[0,0]:=1; a:=0; tt:=0;
for i:=1 to m+1 do
begin
b:=a xor 1; s[0]:=0; s[-1]:=0;
for j:=0 to n do f[b,j]:=0;
for j:=0 to n do s[j]:=s[j-1]+f[a,j];
t:=0;
for j:=i to n do
begin
while (t<=n+1)and(sum[t]<sum[j]-ans) do inc(t);
if t=n+2 then break;
f[b,j]:=(s[j-1]-s[t-1])mod 10007;
end;
tt:=(tt+f[b,n])mod 10007;
a:=b;
end;
writeln(tt);
end.