zoukankan      html  css  js  c++  java
  • BZOJ1044: [HAOI2008]木棍分割 (二分 + DP)

    题意:n根木棍依次连在一起 最多切m个端点 使得最长的一段最小

       在保证最长的最小的情况下 有多少种不同的切法

    题解:第一问傻子都知道二分

       第二问想了一会不会做 但其实就是很简单的dp

       dp[i][j]表示切完第i刀切到第j段后面的的种数

       想了一下觉得空间过不去 然而这个是可以滚动的 因为每一刀的转移都只和前一刀有关系 再优化下时间

       预处理一下last[i]表示在第i个木棍后面切的话 至少要在last[i]这个点及以后也切一下

       跃然纸上的转移 dp[i][j] += dp[i - 1][k]  if(last[j] <= k < j) 但这是个接近n^3的复杂度

       然后发现每次转移 dp[i][j]都是加的相同一段 所以我们可以每次前缀和搞一下

    #include <bits/stdc++.h>
    using namespace std;
    const int mod = 10007;
    
    int n, m;
    int q[50005];
    int sum[50005];
    int last[50005];
    int dp[2][50005];
    int pre[2][50005];
    int ans1, ans2;
    
    int check(int x)
    {
        int res = 0;
        int cnt = 0;
        for(int i = 1; i <= n; i++)
        {
            res += q[i];
            if(res > x) cnt++, res = q[i];
        }
        return cnt;
    }
    
    int main()
    {
        ans2 = 0;
        scanf("%d%d", &n, &m);
        int l = 0, r = 0;
        for(int i = 1; i <= n; i++)
        {
            scanf("%d", &q[i]);
            l = max(l, q[i]); r += q[i];
        }
    
        int mid = l + r >> 1;
        while(l + 1 < r)
        {
            mid = l + r >> 1;
            if(check(mid) <= m) ans1 = mid, r = mid;
            else l = mid;
        }
        if(check(l) <= m) ans1 = l;
    
        int zsum = 0;
        int p = 1;
        for(int i = 1; i <= n; i++)
        {
            zsum += q[i];
            while(zsum > ans1) zsum -= q[p], p++;
            last[i] = p - 1;
            if(last[i] == 0) dp[1][i] = 1;
        }
        ans2 += dp[1][n];
        for(int i = 1; i <= n; i++) pre[1][i] = (dp[1][i] + pre[1][i - 1]) % mod;
    
        for(int i = 2; i <= m + 1; i++)
        {
            memset(dp[i & 1], 0, sizeof(dp[i & 1]));
            pre[i & 1][i - 1] = 0;
    
            for(int j = i; j <= n; j++)
            {
                dp[i & 1][j] = (dp[i & 1][j] + pre[(i - 1) & 1][j - 1]) % mod;
                if(last[j]) dp[i & 1][j] = (dp[i & 1][j] - pre[(i - 1) & 1][last[j] - 1]) % mod;
                dp[i & 1][j] = (dp[i & 1][j] + mod) % mod;
            }
            for(int j = i; j <= n; j++) pre[i & 1][j] = (pre[i & 1][j - 1] + dp[i & 1][j]) % mod;
            ans2 = (ans2 + dp[i & 1][n]) % mod;
        }
    
        printf("%d %d
    ", ans1, ans2);
        return 0;
    }
    View Code

       

       

  • 相关阅读:
    第06组Alpha冲刺(4/6)
    第06组Alpha冲刺(3/6)
    第06组Alpha冲刺(2/6)
    第06组 Alpha冲刺 (1/6)
    08-js函数
    07-数组
    06-js分支
    05-js运算符
    04-js变量
    03-css3D转换
  • 原文地址:https://www.cnblogs.com/lwqq3/p/9774514.html
Copyright © 2011-2022 走看看