BZOJ 1044 木棍分割

Description

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

Input

输入文件第一行有2个数n,m. 接下来n行每行一个正整数Li,表示第i根木棍的长度.

Output

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

Sample Input

3 2
1
1
10

Sample Output

10 2

HINT

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

数据范围

n<=50000, 0<=m<=min(n-1,1000).

1<=Li<=1000.

Source

本题第一问明显可以二分答案(满足可二分性)——二分答案ans贪心检测。

至于第二问,可以用序列dp来解决。f[i][j]表示前i段木棍,分成j份的合法方案数。转移也很好想,f[i][j]=Σf[k][j-1](pre[i]-pre[k]<=ans),pre代表前缀和。看上去复杂度是O(m*n2)。但其实可以优化一下,因为i↑,所有k的下界也↑。所以我们可以利用单调队列,记录对于f[i][j]所有合法的f[k][j-1]的和,以此进行dp。复杂度O(m*n)。

 1 #include<cstdio>
 2 #include<cstdlib>
 3 using namespace std;
 4
 5 #define rhl 10007
 6 #define maxn 50010
 7 #define maxm 1010
 8
 9 int n,m,ans,L[maxn],sum[maxn];
10 short f[maxn][maxm],res[maxn];
11
12 struct node
13 {
14     int a[maxn],*h,*t;
15     node() {h = t = a;}
16
17     inline void push(int k)
18     {
19         *(++t) = k;
20         for (int i = 1;i <= m;++i)
21             (res[i] += f[k][i-1]) %= rhl;
22     }
23
24     inline void pop(int k)
25     {
26         while (sum[k]-sum[*(h+1)] > ans)
27         {
28             for (int i = 1;i <= m;++i)
29                 (res[i] -= f[*(h+1)][i-1]) %= rhl;
30             ++h;
31         }
32     }
33 }team;
34
35 inline bool okay(int l)
36 {
37     int i,j,tot = 0;
38     for (i = 1;i <= n;)
39     {
40         if (tot > m + 1) return false;
41         for (j = i-1;j+1 <= n&&sum[j+1]-sum[i-1] <= l;++j);
42         if (j < i) return false;
43         ++tot; i = j+1;
44     }
45     return tot <= m + 1;
46 }
47
48 inline void dp()
49 {
50     ++m;
51     f[0][0] = 1;
52     team.push(0);
53     for (int i = 1;i <= n;++i)
54     {
55         team.pop(i);
56         for (int j = 1;j <= m;++j) f[i][j] = res[j];
57         team.push(i);
58     }
59     ans = 0;
60     for (int i = 1;i <= m;++i) (ans += f[n][i])%=rhl;
61     ans = ans % rhl + rhl;
62     ans %= rhl;
63 }
64
65 int main()
66 {
67     scanf("%d %d",&n,&m);
68     for (int i = 1;i <= n;++i) scanf("%d",L+i),sum[i] = sum[i-1] + L[i];
69     int l = 1,r = sum[n],mid;
70     while (l <= r)
71     {
72         mid = (l + r) >> 1;
73         if (!okay(mid)) l = mid + 1;
74         else r = mid - 1;
75     }
76     printf("%d ",ans = l);
77     dp();
78     printf("%d",ans);
79     return 0;
80 }

时间: 2024-12-08 09:49:02

BZOJ 1044 木棍分割的相关文章

BZOJ 1044 木棍分割 解题报告(二分+DP)

来到机房刷了一道水(bian’tai)题.题目思想非常简单易懂(我的做法实际上参考了Evensgn 范学长,在此多谢范学长了) 题目摆上: 1044: [HAOI2008]木棍分割 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3162  Solved: 1182[Submit][Status][Discuss] Description 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个

【BZOJ】【1044】【HAOI2008】木棍分割

二分/DP 真是一道好题! 第一问很简单的二分…… 第二问一开始我想成贪心了,其实应该是DP的= = 然后没有注意……又MLE又TLE的……这题要对DP进行时空两方面的优化!! 题解:(by JoeFan) 使用前缀和,令 Sum[i] 为前 i 根木棍的长度和. 令 f[i][j] 为前 i 根木棍中切 j 刀,并且满足最长长度不超过 j 的方案数,那么: 状态转移方程: f[i][j] = Σ f[k][j-1] ((1 <= k <= i-1) &&  (Sum[i] -

1044: [HAOI2008]木棍分割

1044: [HAOI2008]木棍分割 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2161  Solved: 779[Submit][Status][Discuss] Description 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且输出有多少种砍的方法使得总长度最大的一段长度最小. 并将结果m

BZOJ 1044

1044: [HAOI2008]木棍分割Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1393  Solved: 497[Submit][Status] Description 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且输出有多少种砍的方法使得总长度最大的一段长度最小. 并将结果mod 10007..

BZOJ1044: [HAOI2008]木棍分割

1044: [HAOI2008]木棍分割 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1580  Solved: 567[Submit][Status] Description 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且输出有多少种砍的方法使得总长度最大的一段长度最小. 并将结果mod 10007.

【bzoj1044】【HAOI2008】【木棍分割】

1044: [HAOI2008]木棍分割 Time Limit: 10 Sec Memory Limit: 162 MB Submit: 2018 Solved: 730 [Submit][Status][Discuss] Description 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且输出有多少种砍的方法使得总长度最大的一段长度最小. 并将结果m

bzoj1044[HAOI2008]木棍分割 单调队列优化dp

1044: [HAOI2008]木棍分割 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4314  Solved: 1664[Submit][Status][Discuss] Description 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且输出有多少种砍的方法使得总长度最大的一段长度最小. 并将结果

木棍分割[HAOI2008]

题目描述 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且输出有多少种砍的方法使得总长度最大的一段长度最小. 并将结果mod 10007... 输入 输入文件第一行有2个数n,m.接下来n行每行一个正整数Li,表示第i根木棍的长度.n<=50000,0<=m<=min(n-1,1000),1<=Li<=1000. 输出 输出有2个数,

[HAOI2008]木棍分割解题报告

305 . [HAOI2008] 木棍分割 ★★★☆ 输入文件:stick.in 输出文件:stick.out 简单对比 时间限制:3 s 内存限制:64 MB [问题描述] 有n根木棍,第i根木棍的长度为Li,n根木棍依次连结在一起,总共有n-1个连接处.现在允许你最多砍断m个连接处,砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小,并且输出有多少种砍木棍的方法使得总长度最大的一段长度最小. [输入格式] 输入文件第一行有2个数n,m 接下来n行每行一个正整数Li,表示第i根木棍