• 1044: [HAOI2008]木棍分割


    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
    Sample Output
    10 2

    两种砍的方法: (1)(1)(10)和(1 1)(10)
    数据范围
    n<=50000, 0<=m<=min(n-1,1000).
    1<=Li<=1000.

    第一问就直接二分答案

    第二问我们动态规划,f[i,j]表示前i个分成j段有多少种方案

    f[i,j]=sigema(f[k,j-1])(sum[i]-sum[k]<=lim)

    数组要滚动,每次计算f[i,j]时先继承f[i+1,j]的值(因为我是倒着做的),然后把多的减去少的加上就行了

     1 const
     2     maxn=100010;
     3     h=10007;
     4 var
     5     f,a,s:array[0..maxn]of longint;
     6     n,m,lim,ans:longint;
     7  
     8 function flag(x:longint):boolean;
     9 var
    10     i,k,sum:longint;
    11 begin
    12     k:=0;
    13     sum:=0;
    14     for i:=1 to n do
    15       begin
    16         if a[i]>x then exit(false);
    17         if sum+a[i]>x then
    18           begin
    19             inc(k);
    20             sum:=a[i];
    21           end
    22         else inc(sum,a[i]);
    23       end;
    24     if sum>0 then inc(k);
    25     if k>m then exit(false);
    26     exit(true);
    27 end;
    28  
    29 procedure init;
    30 var
    31     i,l,r,mid:longint;
    32 begin
    33     read(n,m);
    34     inc(m);
    35     for i:=1 to n do
    36       begin
    37         read(a[i]);
    38         s[i]:=s[i-1]+a[i];
    39       end;
    40     l:=1;
    41     r:=500000000;
    42     while l<>r do
    43       begin
    44         mid:=(l+r)>>1;
    45         if flag(mid) then r:=mid
    46         else l:=mid+1;
    47       end;
    48     lim:=l;
    49     f[0]:=1;
    50     write(lim,' ');
    51 end;
    52  
    53 procedure work;
    54 var
    55     i,j,l,sum:longint;
    56 begin
    57     for i:=1 to m do
    58       begin
    59         sum:=f[n];
    60         l:=n-1;
    61         for j:=n downto 0 do
    62           begin
    63             dec(sum,f[j]);
    64             f[j]:=0;
    65             while (l>=0) and (s[j]-s[l]<=lim) do
    66               begin
    67                 inc(sum,f[l]);
    68                 dec(l);
    69               end;
    70             f[j]:=sum mod h;
    71           end;
    72         ans:=(ans+f[n])mod h;
    73       end;
    74     write(ans);
    75 end;
    76  
    77 begin
    78     init;
    79     work;
    80 end.
    View Code
  • 相关阅读:
    Ubuntu查看端口占用情况
    在jupyter中添加新的环境
    C++指针
    C++排序:冒泡排序,简单选择排序,直接插入排序,希尔排序,堆排序,归并排序,快速排序
    查找一:C++静态查找
    C++链式队列
    C++顺序循环队列
    C++链式栈
    C++顺序栈
    C++双向循环链表
  • 原文地址:https://www.cnblogs.com/Randolph87/p/3650325.html
Copyright © 2020-2023  润新知