原题传送门http://www.lydsy.com/JudgeOnline/problem.php?id=1044
首先对于第一问,我们可以轻易的用二分答案来搞定,对于每一个二分到的mid值
我们从len[i]开始累加,每到累加值>mid的时候,就累加一个需要砍的次数,然后
比较次数和m的大小关系,然后二分就行了,这里有个小贪心,对于一个len[i],我们
尽量的不让他消耗一次砍得次数,直到非砍不可了才砍。
那么问题就转化成了我们有N个木条的长度,用最多M刀将他们分为不超过ans长度的方案数
我们用w[j,i]代表砍j刀,前i个木条的方案数,那么可以轻易的得到转移方程
w[j,i]:=sigma(w[j-1,k]) sum[i]-sum[k-1]<=ans
其中sum是长度的前缀和
分析下,这个时间复杂度是n*n*m的,明显过不去,那么想下优化
我们可以知道,sum是不变的,换句话说,就是每个转移到I的k是不变的,且是连续区间
那么我们对于每个i,存下pre[i],代表最早pre[i]能更新I,那么我们w[j,i]也存成前缀和,
对于每个w[j,i]就可以o(1)的转移了
而且这道题会卡空间,需要用滚动数组
自己的超时了,照着大神的改了改。。。
/************************************************************** Problem: 1044 User: BLADEVIL Language: Pascal Result: Accepted Time:2040 ms Memory:1208 kb ****************************************************************/ var w :array[0..1,-3..50000] of longint; pre, a, s :array[-1..50000] of longint; last :array[-1..1001] of longint; p, ans2, tot :longint; max, tmp :longint; i, j, h, k :longint; l, r, mid, ans :longint; n, m :longint; function check(x:longint):boolean; var i :longint; begin if max>x then exit(false); tmp:=0; tot:=0; for i:=1 to n do begin if tmp+a[i]<=x then tmp:=tmp+a[i] else begin tmp:=a[i]; inc(tot); if tot>m then exit(false); end; end; exit(true); end; begin readln(n,m); if n=0 then begin writeln(0,' ',1); exit; end; for i:=1 to n do begin readln(a[i]); s[i]:=s[i-1]+a[i]; if max<a[i] then max:=a[i]; end; l:=1; r:=s[n]; while l<r do begin if l=r-1 then begin if check(l) then ans:=l else ans:=r; break; end; mid:=(l+r) shr 1; if check(mid) then r:=mid else l:=mid; end; tmp:=0; tot:=0; for i:=1 to n do begin if tmp+a[i]>ans then begin tmp:=a[i]; inc(tot); last[tot]:=i-1; end else tmp:=tmp+a[i]; end; for i:=tot+1 to m+1 do last[i]:=n; h:=1; for i:=1 to n do begin while s[i]-s[h]>ans do inc(h); pre[i]:=h; end; for i:=1 to last[1] do w[1,i]:=w[1,i-1]+1; for i:=last[1]+1 to last[2] do w[1,i]:=w[1,i-1]; l:=1; for i:=2 to m+1 do begin k:=l; l:=k xor 1; w[l,i]:=1; p:=1; for j:=i+1 to last[i] do begin p:=w[k,j-1]-w[k,pre[j]-1]; w[l,j]:=(w[l,j-1]+p) mod 10007; end; if last[i]=n then ans2:=(ans2+p) mod 10007 else begin for j:=last[i]+1 to last[i+1] do w[l,j]:=w[l,j-1]; end; end; writeln(ans,' ',(ans2 mod 10007+10007) mod 10007); end.