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;
}

 

posted @ 2018-06-06 17:45  Zinn  阅读(184)  评论(0编辑  收藏  举报