bzoj1044木棍分割

题目链接

第一小问,显然二分一下就好,

然后有了答案了我们$dp$计算方案数

/**************************************************************
    Problem: 1044
    User: zhangheran
    Language: C++
    Result: Accepted
    Time:6844 ms
    Memory:3244 kb
****************************************************************/
 
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define int long long
const int mod=10007;
int n,m;
int l[50010],num[50010];
int ans;int ans2;
int g[50010];
int f[50010];
int dp[50010];
bool check(long long x)
{
//  if(x*m<num[n]) return false;
//  printf("%lld\n",x);
    int now=1;int len=0;
    for(int i=1;i<=n;i++)
        if(l[i]>x) return false;
        else if(len+l[i]>x) now++,len=l[i];
        else len+=l[i];
    return now<=m;
}
void work()
{   
    long long lef=1;long long rig=50000000;
    while(lef<=rig){
        long long mid=lef+rig>>1;
        if(check(mid)) ans=mid,rig=mid-1;
        else lef=mid+1;
//      printf("%lld %lld %d\n",lef,rig,ans);
    }
    printf("%lld ",ans);
    return ;
}
 
signed main()
{
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++) scanf("%lld",&l[i]),num[i]=num[i-1]+l[i];  
    m++;
    work();
    int now=0;
    for(int i=1;i<=n;i++){
      while(num[i]-num[now]>ans) now++;
      g[i]=now;}
//  printf("%d ",now);
//for(int i=1;i<=n;i++) printf("%d ",g[i]);
    for(int i=0;i<=n;i++) dp[i]=1;
    for(int i=1;i<=m;i++){
        for(int j=1;j<=n;j++) f[j]=(dp[j-1]-dp[g[j]-1])%mod;dp[0]=0;
        for(int j=1;j<=n;j++) dp[j]=f[j]+dp[j-1];
        ans2=(ans2+f[n])%mod;
    }
    printf("%lld",ans2);
    return 0; 
} 

 

posted @ 2018-07-27 21:03  米罗偕涯  阅读(337)  评论(0编辑  收藏  举报