• [HAOI2008]木棍分割


    第一问直接使用二分 (+) 贪心即可。

    对于第二问,我们可以考虑一个 (dp),令 (dp_{i, j, k}) 表示当前选到第 (i) 根木棍,已经分成了 (j) 段的方案数,当前这一段的长度和为 (k) 的方案,那么就有转移就十分显然了。

    到这里我们发现这个 (dp) 的复杂度只能从状态下手,这个时候我们一般会考虑压掉一维状态并改写状态的意义。可以发现我们令 (dp_{i, j}) 表示当前选到第 (i) 根木棍,已经分成了 (j) 段的方案数,这样是可以转移的:

    [dp_{i, j} = sumlimits_{k = {li}_i} dp_{k, j - 1} ]

    (mx) 为第一问的答案,其中 ({li}_i) 表示 (i) 左边第一个 (sumlimits_{j = l} ^ i a_j > mx)(l),上面那个转移可以使用前缀和优化,再使用滚动数组优化掉空间即可。

    #include<bits/stdc++.h>
    using namespace std;
    #define N 50000 + 5
    #define Mod 10007
    #define rep(i, l, r) for(int i = l; i <= r; ++i)
    int n, m, l, r, p, ans, a[N], s[N], li[N], dp[2][N], S[2][N];
    int read(){
        char c; int x = 0, f = 1;
        c = getchar();
        while(c > '9' || c < '0'){ if(c == '-') f = -1; c = getchar();}
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    }
    bool check(int k){
        int cnt = 0, tmp = 0;
        rep(i, 1, n){
            if(tmp + a[i] > k) ++cnt, tmp = a[i];
            else tmp += a[i];
        }
        return cnt <= m;
    }
    int Inc(int a, int b){
        return (a += b) >= Mod ? a - Mod : a;
    }
    int Dec(int a, int b){
        return (a -= b) < 0 ? a + Mod : a;
    }
    int main(){
        n = read(), m = read();
        rep(i, 1, n) a[i] = read(), s[i] = s[i - 1] + a[i], l = max(l, a[i]), r += a[i];
        while(l < r){
            int Mid = (l + r) / 2;
            if(check(Mid)) r = Mid;
            else l = Mid + 1;
        }
        printf("%d ", r);
        rep(i, 1, n){
            while(p < i && s[i] - s[p] > r) ++p;
            li[i] = p;
        }
        p = 0, ans = (s[n] <= r);
        rep(i, 1, n) dp[1][i] = (s[i] <= r), S[1][i] = Inc(S[1][i - 1], dp[1][i]);
        rep(i, 2, m + 1){
            rep(j, 1, n){
                dp[p][j] = S[p ^ 1][j - 1];
                if(li[j] > 0) dp[p][j] = Dec(dp[p][j], S[p ^ 1][li[j] - 1]);
            } 
            rep(j, 1, n) S[p][j] = Inc(S[p][j - 1], dp[p][j]);
            p ^= 1, ans = Inc(ans, dp[p ^ 1][n]);
            rep(j, 1, n) dp[p][j] = 0;
        }
        printf("%d", ans);
        return 0;
    }
    
    GO!
  • 相关阅读:
    objcopy使用
    linux中的strip命令简介
    strace命令详解
    bash执行顺序:alias --> function --> builtin --> program
    Ubuntu下安装docker
    uvm中类继承和phase
    error和exception有什么区别?
    sleep() 和 wait() 有什么区别?
    CSS3实现环形进度条?
    请写出你最常见到的5个runtime exception?
  • 原文地址:https://www.cnblogs.com/Go7338395/p/13487603.html
Copyright © 2020-2023  润新知