zoukankan      html  css  js  c++  java
  • 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比较小的话这个方法相当实用。

    举个例子

    k序列和

    【问题描述】

    对于一个给定的序列,将其分为k个部分,求各部分和的最大值的最小值。

    【问题分析】

    可采用二分答案的思想,设出一个答案ans,循环将和不超过ans的几个数分为一部分。直到最后若可以分为k部分则减小上界,反之增加下界。直到确定答案。

    AYYZOJ 1588

     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分。

     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 划分序列 

    交上同样的程序就过了。。

     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
  • 相关阅读:
    洛谷1509 找啊找啊找GF
    要怎样努力,才能成为很厉害的人?
    随笔
    2018NOIP模拟题 曲线
    洛谷4147 玉蟾宫
    洛谷2258 子矩阵
    Vijos 纸牌
    [leetcode] Word Break
    [leetcode] Maximum Binary Tree
    [leetcode] Binary Tree Preorder Traversal
  • 原文地址:https://www.cnblogs.com/vacation/p/6063723.html
Copyright © 2011-2022 走看看