k序列和

二分答案是參數搜索的一個改善。
是這樣,對於一個問題,若是它的答案具備單調性質(即若是i不可行,那麼大於i的解都不可行,而小於i的解有可能可行),進而用二分的方法枚舉答案,再判斷答案是否可行,直到求到符合條件爲止。
例如:問題的答案範圍是1到w之間的一個整數,求最小解,那麼咱們設s=1,t=w,以後mid=(s+t)整除2。而後判斷當解是mid的時候這個問題能不能解決,若是能解決則和最優解比較,而且範圍縮小到s到mid-1之間(由於即便這個範圍沒有解,那麼mid是最小解);若是不能解決問題,則最小解確定比mid要大,則範圍縮小到mid+1和t之間。如此反覆知道s=t時判斷完結束。
這時候那個記錄最優解的變量必定記錄的是可以達到的最優解。
羅嗦了這麼多,簡單來講就是假設一個答案,而後判斷是否可行,而且不斷縮小範圍。
二分枚舉答案的時間複雜度是O(log2 n),而判斷時間是O(K)的話總的時間複雜度是O(Klog2 n)若是某個問題符合這個性質而且K比較小的話這個方法至關實用。ide

舉個例子spa

k序列和code

【問題描述】blog

對於一個給定的序列,將其分爲k個部分,求各部分和的最大值的最小值。input

【問題分析】it

可採用二分答案的思想,設出一個答案ans,循環將和不超過ans的幾個數分爲一部分。直到最後若能夠分爲k部分則減少上界,反之增長下界。直到肯定答案。io

AYYZOJ 1588event

 1 var
 2   n,k,i,p,l,r,m,s:longint;
 3   a:array[1..100005] of longint;
 4 begin
 5   readln(n,k);
 6   for i:=1 to n do
 7   begin
 8     read(a[i]);
 9     inc(r,a[i]);
10   end;
11   while r-l>1 do
12   begin
13     m:=(l+r) shr 1;
14     s:=0;  p:=0;
15     for i:=1 to n do
16       if s+a[i]<=m then s:=s+a[i]
17         else begin inc(p); s:=a[i]; end;
18     if p+1>k then l:=m else r:=m;
19   end;
20   writeln(r);
21 end.
22 // 65分。。
23 原程序輸出 r   ----> 65
24 更改輸出爲 l+1 ----> 65
25 原程序循環條件 while r-l>1 do  if p+1>k then l:=m else r:=m;
26 改成 while l<r do  if p+1>k then l:=m+1 else r:=m-1;  ------> 55
27 只改爲 while l<r 死循環
收入計劃

令我鬱悶的是不知上面的程序哪裏不對,只有65分。function

 1 var
 2   l,r,mid,n,m,i:longint;
 3   a,b:array[1..100000] of longint;
 4 function check(p:longint):boolean;
 5 var
 6   i,pre,tot:longint;
 7 begin
 8   tot:=m;
 9   pre:=0;
10   i:=1;
11   while i<=n do
12    begin
13      if pre+a[i]<=p then
14       begin
15         pre:=pre+a[i];
16         inc(i);
17       end
18      else
19       begin
20         pre:=0;
21         dec(tot);
22         if tot=0 then exit(false);
23       end;
24    end;
25   exit(true);
26 end;
27 begin
28   readln(n,m);
29   r:=0;
30   for i:=1 to n do
31    begin
32      readln(a[i]);
33      inc(r,a[i]);
34    end;
35   l:=0;
36   while l<r do
37    begin
38      mid:=(l+r)>>1;
39      if check(mid) then r:=mid else l:=mid+1;
40    end;
41  writeln(l);
42 end.
100

 

COGS 917 劃分序列 class

交上一樣的程序就過了。。

 1 var
 2   n,k,i,p,l,r,m,s:longint;
 3   a:array[1..100000] of longint;
 4 begin
 5 assign(input,'seqa.in');
 6 reset(input);
 7 assign(output,'seqa.out');
 8 rewrite(output);
 9   readln(n,k);
10   for i:=1 to n do
11   begin
12     read(a[i]); inc(r,a[i]);
13   end;
14   while r-l>1 do begin
15     m:=(l+r) shr 1;
16     s:=0; p:=0;
17     for i:=1 to n do
18       if s+a[i]<=m then s:=s+a[i]
19         else begin inc(p); s:=a[i]; end;
20     if p+1>k then l:=m else r:=m;
21   end;
22   writeln(r);
23 close(input);
24 close(output);
25 end.
100
相關文章
相關標籤/搜索