BZOJ P1044 [HAOI2008]木棍分割【二分答案】【动态规划】

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define rep(i,x,y) for(int i=(x);i<=(y);i++)
#define repl(i,x,y) for(int i=(x);i<(y);i++)
#define repd(i,x,y) for(int i=(x);i>=(y);i--)
using namespace std;

const int N=5e4+5;
const int Mod=1e4+7;

int n,m,mlen,len[N],sum[N],f[N][2];

inline int read() {
    int x=0;char ch=getchar();bool f=0;
    while(ch>'9'||ch<'0'){if(ch=='-')f=1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return f?-x:x;
}

inline int sub(int x,int y) { return x-y<0?x-y+Mod:x-y;}
inline int add(int x,int y) { return x+y>=Mod?x+y-Mod:x+y;}

bool check(int x) {
	if(x<mlen) return false;
	
	int tot=0,cnt=0;
	
	rep(i,1,n) {
		if(tot+len[i]>x) {
			if(++cnt>m) return false;tot=0;
		}
		tot+=len[i];
	}
	
	return true;
}

int main() {
	n=read(),m=read();
	rep(i,1,n) {
		len[i]=read();
		sum[i]=sum[i-1]+len[i];mlen=max(mlen,len[i]);
	}
	
	int l=0,r=sum[n];
	while(l<=r) {
		int mid=l+r>>1;
		if(check(mid)) r=mid-1;
		else l=mid+1;
	}
	
	int ans1=l,ans2=0,cur=0;
	
	rep(i,0,m) {
		int id=1,tot=0;
		rep(j,1,n) {
			if(i==0) {
				if(sum[j]<=ans1) f[j][0]=1;
				else f[j][cur]=0;
			} else {
				while(id<j&&sum[j]-sum[id]>ans1) {
					tot=sub(tot,f[id][cur^1]);++id;
				}
				f[j][cur]=tot;
			}
			tot=add(tot,f[j][cur^1]);
		}
		ans2=add(ans2,f[n][cur]);cur^=1;
	}
	
	printf("%d %d",ans1,ans2);
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/yanzhenhuai/article/details/82762138