zoukankan      html  css  js  c++  java
  • bzoj 1044 贪心二分+DP

    原题传送门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.
  • 相关阅读:
    CentOS部署ElasticSearch7.6.1集群
    Linux安装Elasticsearch7.x
    ElasticSearch安装为Windows服务
    SolrNet Group分组 实现
    ubuntu 下安装sublime
    LeetCode 3: Longest Substring Without Repeating Characters
    LeetCode 179: Largest Number
    LeetCode 1: Two Sum
    LeetCode 190: Reverse Bits
    LeetCode 7: Reverse Integer
  • 原文地址:https://www.cnblogs.com/BLADEVIL/p/3435977.html
Copyright © 2011-2022 走看看