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

   

   

原文地址:https://www.cnblogs.com/lwqq3/p/9774514.html