P2511 [HAOI2008]木棍分割 题解

思路

这道题是一个比较经典的题,特别是通过一个问题的约束去求解下一个问题的这个思维。

对于第一问,由于是要求总长度最大的那一段最小,不难发现其具有单调性,我们可以采用二分解决。我们二分最大的那段的长度 len,贪心地去选取:每一段只要不超过 len,长度越大越好,合法性的话只要判断最后的段数是否小于等于 m+1 即可(题目说最多切 m 刀,也就等价于最多切成 m+1 段)。

第二问,我们采用动态规划算法。首先对原数组做一个前缀和,得到 sumi 表示前 i 根木棍的总长度。我们设 fi,j 为前 j 根木棍分成 i 组的方案数,那么有:fi,j=k=tj1fi1,k 其中 t 为满足 sumjsumt 的最左边的 t,而 t 可以通过预处理计算,预处理可以采用二分的形式(我的代码里用的是 O(n) 的方法,对于逐渐增大的 j,变量 t 是递增的)。

最后的答案就是 i=1m+1fi,n,时间复杂度 O(n3)

我们发现转移过来的是连续的一段区间,所以我们采用前缀和优化,用 g 数组表示前缀和,有 gi,j=k=1jfi,k

那么转移式子变成了:fi,j=gi1,j1gi1,k1

思路要点

  1. 要你求多个不同的问题时,不妨看看能否先求出其中任意一个,再通过这一个求出其它的。

    像这一题就是先求出第一问,再通过第一问的约束求出第二问。

  2. 动态规划需要较低的转移时间且能转移过来的是一段区间的话,可以试一下能否用前缀和优化。

代码

#include <bits/stdc++.h>
#define re register
#define L(i, a, b) for(re int i = a; i <= b; i++)
#define R(i, a, b) for(re int i = a; i >= b; i--)
using namespace std;
const int N = 50010, M = 1010, mod = 10007;
int n, m, ans, len, a[N], p[N], sum[N], f[N], g[N];//f和g两数组第一维没用,优化掉了
void upd(int &x, const int y){
    x = y;
    if(x < 0) x += mod;//加法比取模快多了,等价于 x %= mod
    if(x >= mod) x -= mod;//减法比取模快多了,等价于 x = (x % mod + mod) % mod
}
bool check(const int x){
    re int cnt = 0, sum = 0;
    L(i, 1, n){
        if(a[i] > x) return 0;
        if(sum + a[i] > x) sum = a[i], cnt++;
        else sum += a[i];
    }
    return cnt < m;//等价于cnt + 1 <= m,因为最后一段没算进去,所以cnt要加1
}
int main(){
    scanf("%d%d", &n, &m), m++;
    L(i, 1, n) scanf("%d", &a[i]);
    re int l = 1, r = 1e9, id = 1;
    while(l <= r){
        int mid = l + r >> 1;
        if(check(mid)) r = mid - 1, len = mid;//len为第一问答案
        else l = mid + 1;
    }
    L(i, 1, n){
        sum[i] = sum[i - 1] + a[i];
        if(sum[i] <= len) f[i] = 1;
        while(id <= n && sum[i] - sum[id] > len) id++;
        p[i] = id;
    }
    L(j, 1, n) upd(g[j], g[j - 1] + f[j]);
    upd(ans, ans + f[n]);
    L(i, 2, m){
        L(j, 1, n) upd(f[j], g[j - 1] - (p[j] - 1 < 0? 0 : g[p[j] - 1]));
        L(j, 1, n) upd(g[j], g[j - 1] + f[j]);
        upd(ans, ans + f[n]);
    }
    printf("%d %d\n", len, ans);
    return 0;
}
posted @   徐子洋  阅读(31)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示