bzoj1044 [HAOI2008]木棍分割——前缀和优化DP

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1044

咳咳...终于A了...

居然没注意到正着找pos是n方会TLE...所以要倒着找pos;

二分还写错了,改了半天...

小心前缀和取模后相减变成负数!!!!!!!!!

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int const maxn=50005,mod=10007;
int n,m,a[maxn],s[maxn][3],f[maxn][3],ans,mn,sum,l,r,pos[maxn];
bool pd(int x)
{
    int s=0,cnt=0;
    for(int i=1;i<=n;i++)
    {
        if(s+a[i]>x)
        {
            cnt++;
            s=0;
        }
        s+=a[i];
    }
    return cnt<=m;//m!!
    return 1;
}
void solve1()
{
    r=s[n][0];
    int mid=(l+r)>>1;
    while (l<=r)
    {
        if (pd(mid)) mn=mid,r=mid-1;
        else l=mid+1;
        mid=(l+r)>>1;
    }
}
void solve2()
{
    for(int i=1;i<=n;i++)
    {
        if(s[i][0]<=mn)f[i][0]=1;
        else break;
    }
    for (int i=1;i<=n;i++)
    {
        if (s[i][0]<=mn) continue;
        for (int j=i-1;j>=0;j--)
        if (s[i][0]-s[j][0]>mn) {pos[i]=j+1;break;}
//        for(int j=0;j<i;j++)
//            if(s[i][0]-s[j][0]<=mn){pos[i]=j;break;}//TLE!!!(n方)
    }
    bool x=0;
    while(m--)
    {
        for(int i=1;i<=n;i++)
            s[i][x]=(s[i-1][x]+f[i][x])%mod;//
        x=!x;
        for(int i=1;i<=n;i++)
            f[i][x]=(s[i-1][!x]-s[max(pos[i]-1,0)][!x]+mod)%mod;//i-1!    //pos[i]-1!  //mod后小心负数!!!!!
        (ans+=f[n][x])%=mod;
    }
    printf("%d %d",mn,ans);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]),s[i][0]=s[i-1][0]+a[i],l=max(l,a[i]);
    solve1();
    solve2();
    return 0;
}

原文地址:https://www.cnblogs.com/Zinn/p/9146430.html

时间: 2024-10-08 18:11:22

bzoj1044 [HAOI2008]木棍分割——前缀和优化DP的相关文章

bzoj1044[HAOI2008]木棍分割 单调队列优化dp

1044: [HAOI2008]木棍分割 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4314  Solved: 1664[Submit][Status][Discuss] Description 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且输出有多少种砍的方法使得总长度最大的一段长度最小. 并将结果

BZOJ1044: [HAOI2008]木棍分割

1044: [HAOI2008]木棍分割 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1580  Solved: 567[Submit][Status] Description 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且输出有多少种砍的方法使得总长度最大的一段长度最小. 并将结果mod 10007.

1044: [HAOI2008]木棍分割

1044: [HAOI2008]木棍分割 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2161  Solved: 779[Submit][Status][Discuss] Description 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且输出有多少种砍的方法使得总长度最大的一段长度最小. 并将结果m

[HAOI2008]木棍分割解题报告

305 . [HAOI2008] 木棍分割 ★★★☆ 输入文件:stick.in 输出文件:stick.out 简单对比 时间限制:3 s 内存限制:64 MB [问题描述] 有n根木棍,第i根木棍的长度为Li,n根木棍依次连结在一起,总共有n-1个连接处.现在允许你最多砍断m个连接处,砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小,并且输出有多少种砍木棍的方法使得总长度最大的一段长度最小. [输入格式] 输入文件第一行有2个数n,m 接下来n行每行一个正整数Li,表示第i根木棍

HDU-5332(前缀和优化dp/CDQ+NTT)

HDU-5332(CDQ+NTT/前缀和优化dp) 考虑依次求出\(i\)个点的答案 假设当前有\(i-1\)个点,枚举第\(i\)个点前面的点数\(j\),则\(dp_i=dp_{i-j-1}\cdot (j+1)^2\cdot C(i-1,i-j-1)\cdot j!\) 直接转移是\(O(n^2)\)的,可以看到是一个\(dp\)转移与差值有关,所以可以用\(CDQ\)分治+\(NTT\)解决 关于这种简单粗暴的做法,模板题HDU-5730 题解 以下是暴力的代码 #include<bit

[HAOI2008] 木棍分割 - dp,前缀和,双指针

Solution 第一问二分模板题,利用第一问答案做第二问 \(O(n^2m)\) 的 dp 是显然的,考虑用前缀和优化,用双指针预处理出转移位置的边界,于是每次转移复杂度 \(O(1)\),总体复杂度 \(O(nm)\) #include <bits/stdc++.h> using namespace std; #define int long long const int mod = 10007; const int N = 50005; int n,m,l[N],f[N],g[N],s[

bzoj2431: [HAOI2009]逆序对数列(前缀和优化dp)

2431: [HAOI2009]逆序对数列 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 2312  Solved: 1330[Submit][Status][Discuss] Description 对于一个数列{ai},如果有i<j且ai>aj,那么我们称ai与aj为一对逆序对数.若对于任意一个由1~n自然数组成的 数列,可以很容易求出有多少个逆序对数.那么逆序对数为k的这样自然数数列到底有多少个? Input 第一行为两个整数n,k. Ou

P5241 序列(滚动数组+前缀和优化dp)

P5241 序列 挺神仙的一题 看看除了dp好像没什么其他办法了 想着怎么构个具体的图出来,然鹅不太现实. 于是我们想办法用几个参数来表示dp数组 加了几条边肯定要的吧,于是加个参数$i$表示已加了$i$条边 这显然是不够的.于是我们又想:强连通分量.....连通块....... 于是加个$j$表示还有$j$个强连通分量 于是dp数组为$f[i][j]$ 这是我们发现一个问题,状态$f[i][j]$不一定是合法的. 那dp不就GG了吗 再次撕烤,我们发现每次加上的边无非就3种情况: 1.把2个强

【bzoj1044】[HAOI2008]木棍分割 二分+dp

题目描述 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且输出有多少种砍的方法使得总长度最大的一段长度最小. 并将结果mod 10007... 输入 输入文件第一行有2个数n,m.接下来n行每行一个正整数Li,表示第i根木棍的长度.n<=50000,0<=m<=min(n-1,1000),1<=Li<=1000. 输出 输出有2个数,