BZOJ1044: [HAOI2008]木棍分割
1044: [HAOI2008]木棍分割
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1580 Solved: 567
[Submit][Status]
Description
有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且输出有多少种砍的方法使得总长度最大的一段长度最小. 并将结果mod 10007。。。
Input
输入文件第一行有2个数n,m. 接下来n行每行一个正整数Li,表示第i根木棍的长度.
Output
输出有2个数, 第一个数是总长度最大的一段的长度最小值, 第二个数是有多少种砍的方法使得满足条件.
Sample Input
3 2
1
1
10
1
1
10
Sample Output
10 2
两种砍的方法: (1)(1)(10)和(1 1)(10)
数据范围
n<=50000, 0<=m<=min(n-1,1000).
1<=Li<=1000.
两种砍的方法: (1)(1)(10)和(1 1)(10)
数据范围
n<=50000, 0<=m<=min(n-1,1000).
1<=Li<=1000.
HINT
Source
题解:
第一问二分+贪心可以得出
第二份朴素的话最坏情况下是O(mn^2)的,但考虑到每一个接点有pre[i],表示满足s[i]-s[j]<=ans的最大j,这样转移的时候
有f[i,j]=sigma(f[k,j-1])(pre[i]<=k<=i-1),考虑到pre[i]是单增的的,所以我们可以用单调队列来搞,优化到O(mn),不过也可以不用队列,
只用一个临时变量来记录当前时刻有用的节点的权值和
下面说一些题外话:
1.感觉此题很难写
2.写程序的时候,一要易懂,不容易出错,而才是简短,优美,不要一上来就想着可以怎么怎么减少代码,否则会把自己搞晕
代码:
1 const maxn=50000+100;p=10007; 2 var i,j,n,m,x,ans,cnt,l,r,mid,t,sum:longint; 3 q,pre,len,s:array[0..maxn] of longint; 4 f:array[0..maxn,0..1] of longint; 5 procedure init; 6 begin 7 readln(n,m); 8 for i:=1 to n do begin readln(len[i]);s[i]:=s[i-1]+len[i];end; 9 s[n+1]:=maxlongint; 10 end; 11 function test(x:longint):boolean; 12 var i,j,sum:longint; 13 begin 14 sum:=0;j:=0; 15 for i:=1 to n do 16 if sum+len[i]<=x then inc(sum,len[i]) 17 else begin inc(j);sum:=len[i];end; 18 exit(j<=m); 19 end; 20 procedure main; 21 begin 22 l:=0;r:=1000000000; 23 while l<r do 24 begin 25 mid:=(l+r)>>1; 26 if test(mid) then r:=mid else l:=mid+1; 27 end; 28 ans:=l; 29 j:=0; 30 for i:=1 to n do 31 begin 32 while s[i]-s[j]>ans do inc(j); 33 pre[i]:=j; 34 end; 35 fillchar(f,sizeof(f),0); 36 i:=1;while s[i]<=ans do begin f[i,0]:=1;inc(i);end; 37 t:=0;cnt:=0; 38 for i:=1 to m do 39 begin 40 t:=1-t; 41 l:=0;r:=0;sum:=0; 42 for j:=1 to n do 43 begin 44 while (l<r) and (q[l]<pre[j]) do begin sum:=(sum-f[q[l],1-t]+p) mod p;inc(l);end; 45 f[j,t]:=sum; 46 inc(r);q[r]:=j;sum:=(sum+f[q[r],1-t]) mod p; 47 end; 48 cnt:=(cnt+f[n,t]) mod p; 49 end; 50 writeln(ans,' ',cnt); 51 end; 52 begin 53 assign(input,'input.txt');assign(output,'output.txt'); 54 reset(input);rewrite(output); 55 init; 56 main; 57 close(input);close(output); 58 end.