BZOJ 1044 [HAOI2008]木棍分割

题解:

第一问二分答案

第二问用f[i][j]表示前i块分成j段的方案数

但是MLE

于是改变枚举顺序

先枚举j,然后i这一层用滚动数组优化

f[i][j]=sigma f[k][j-1](sum[i]-sum[k]<=ans)

决策是一段区间,而且左端点单调,搞个指针维护最左的决策点

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100009;
const int mm=10007;

int n,m;
int s[maxn]={0};

int tot=0;
int l=0,r=0,mid=0,ans=0;

int f[maxn]={0};
int g[maxn]={0};

int Isok(){
	int last=0,cnt=0;
	for(int i=1;i<=n;++i){
		if(s[i]-s[last]>mid){
			++cnt;last=i-1;
		}
	}
	++cnt;
	if(cnt>m)return 0;
	else return 1;
}

int main(){
	scanf("%d%d",&n,&m);++m;
	for(int i=1;i<=n;++i){
		scanf("%d",&s[i]);
		l=max(l,s[i]);
		s[i]+=s[i-1];
	}
	
	r=1000000000;
	while(l<=r){
		mid=(l+r)>>1;
		if(Isok()){
			ans=mid;
			r=mid-1;
		}else{
			l=mid+1;
		}
	}
	printf("%d ",ans);
	
	for(int i=1;i<=n;++i){
		if(s[i]<=ans)g[i]=1;
		else g[i]=0;
	}
	for(int j=2;j<=m;++j){
		for(int i=1;i<=j-1;++i)f[j]=0;
		int tm=g[j-1],last=j-1;
		for(int i=j;i<=n;++i){
			while((s[i]-s[last]>ans)){
				tm=(tm-g[last]+mm)%mm;++last;
			}
			f[i]=tm;
			tm=(tm+g[i])%mm;
		}
		tot=(tot+f[n])%mm;
//		for(int i=1;i<=n;++i)cout<<f[i]<<' ';
//		cout<<endl;
		for(int i=1;i<=n;++i)g[i]=f[i];
	}
	
	printf("%d\n",tot);
	return 0;
}

  

 

posted @ 2018-03-04 08:56  ws_zzy  阅读(163)  评论(0编辑  收藏  举报