BZOJ 1044 木棍分割(二分答案 + DP优化)

题目链接  木棍分割

1044: [HAOI2008]木棍分割

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 3830  Solved: 1453
[Submit][Status][Discuss]

Description

  有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连
接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且输出有多少种砍的方法使得总长
度最大的一段长度最小. 并将结果mod 10007。。。

Input

  输入文件第一行有2个数n,m.接下来n行每行一个正整数Li,表示第i根木棍的长度.n<=50000,0<=m<=min(n-1,10
00),1<=Li<=1000.

Output

  输出有2个数, 第一个数是总长度最大的一段的长度最小值, 第二个数是有多少种砍的方法使得满足条件.

Sample Input

3 2
1
1
10

Sample Output

10 2

HINT

两种砍的方法: (1)(1)(10)和(1 1)(10)

Source

第一个问题显然用二分解决,答案为len

第二个问题考虑DP,f[i][j]表示前i根木棒切j刀之后长度最大的一段不超过len的方案数。

则状态转移方程为  f[i][j] = sum(f[k][j - 1])

其中k必须满足  s[i] - s[k] <= len

这样做的话空间复杂度和时间复杂度都超过了限制,所以我们需要优化

空间复杂度方面,因为f[i][j]是从f[i][j - 1]推导而来,所以f的第二维可以用滚动数组来代替。

时间复杂度方面,我们发现大量的时间浪费在判断s[i] - s[k] <= len上,

因为随着j的递增每次符合s[i] - s[k] <= len的k的最大值是不下降的,

那么维护一个类似two-pointer的东西就可以了。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)

typedef long long LL;

const int N   = 50010;
const int mod = 10007;


int n, m;
int a[N], s[N], f[N][2];
int l, r, ans;
int len, cnt;
int k, now;

inline bool check(int x){
	int now = a[1], ret = 0;
	rep(i, 2, n){
		if (now + a[i] <= x){
			now += a[i];
		}

		else{
			now = a[i];
			++ret;
		}
	}

	return ret <= m;
}       


int main(){

	scanf("%d%d", &n, &m);
	rep(i, 1, n){
		scanf("%d", a + i);
		l = max(l, a[i]);
		r += a[i];
		s[i] = s[i - 1] + a[i];
	}

	l = 0, r = 1e8;

	while (l + 1 < r){
		int mid = (l + r) >> 1;
		if (check(mid)) r = mid;
		else l = mid + 1;
	}

	if (check(l)) len = l; else len = r;

	rep(i, 0, m){
		cnt = 0;
		k = 1;
		rep(j, 1, n){
			if (i == 0){
				if (s[j] <= len) f[j][now] = 1;
				else f[j][now] = 0;
			}

			else{
				while (k < j && s[j] - s[k] > len){
					cnt -= f[k][now ^ 1];
					cnt = (cnt + mod) % mod;
					++k;
				}
				f[j][now] = cnt;
			}

			cnt = (cnt + f[j][now ^ 1]) % mod;
		}

		(ans += f[n][now]) %= mod;
		now ^= 1;
	}

	printf("%d %d\n", len, ans);
	return 0;
}

 

posted @ 2017-07-31 10:47  cxhscst2  阅读(438)  评论(0编辑  收藏  举报