[BZOJ1044][HAOI2008]木棍分割 二分+贪心+dp+前缀和优化

Posted wls001

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ1044][HAOI2008]木棍分割 二分+贪心+dp+前缀和优化相关的知识,希望对你有一定的参考价值。

1044: [HAOI2008]木棍分割

Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 4112  Solved: 1577 [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)

 

先二分出答案,然后设f[i][j]表示第i个点切断,切断了j次的方案数,j可以滚动。

用s[i]求出a的前缀和,用p[i]表示第i个位置最左侧的可切割点,用add[i]表示f的前缀和。

技术分享
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<cstdlib>
 5 #include<cmath>
 6 #include<algorithm>
 7 #define mod 10007
 8 using namespace std;
 9 int n,m;
10 int a[50005];
11 int sum;
12 bool check(int now) {
13     int t=0,b=0;
14     for(int i=1;i<=n;i++) {
15         if(a[i]>now) return 0;
16         if(t+a[i]>now) {
17             b++;
18             t=a[i];
19         }
20         else t+=a[i];
21     }
22     return b<=m;
23 }
24 int f[50005];
25 int s[50005];
26 int add[50005],p[50005];
27 int main() {
28     scanf("%d%d",&n,&m);
29     for(int i=1;i<=n;i++){scanf("%d",&a[i]); sum+=a[i];s[i]=s[i-1]+a[i];}
30     int l=0,r=sum;
31     while(l<=r) {
32         int mid=(l+r)>>1;
33         if(check(mid)) r=mid-1;
34         else l=mid+1;
35     }
36     int ans1=r+1;
37     printf("%d ",ans1);
38     int ans2=0;
39     for(int i=1;i<=n;i++) if(s[i]<=ans1) add[i]=add[i-1]+1;else add[i]=add[i-1];
40     if(s[n]<=ans1) ans2++;
41     for(int i=1;i<=n;i++) {
42         int can=s[i]-ans1;
43         int t=lower_bound(s+1,s+i,can)-s;
44         p[i]=t;
45     }
46     for(int j=1;j<=m;j++) {
47         for(int i=1;i<=n;i++) {
48             f[i]=(add[i-1]-add[max(0,p[i]-1)]+mod)%mod;
49         }
50         ans2+=f[n];ans2%=mod;
51         for(int i=1;i<=n;i++) add[i]=(add[i-1]+f[i])%mod;
52     }
53     printf("%d",ans2);
54 }
View Code

 




以上是关于[BZOJ1044][HAOI2008]木棍分割 二分+贪心+dp+前缀和优化的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ1044[HAOI2008]木棍分割 二分+DP

[BZOJ1044][HAOI2008]木棍分割 二分+贪心+dp+前缀和优化

BZOJ1044: [HAOI2008]木棍分割 二分+区间DP

bzoj 1044 [HAOI2008]木棍分割(二分+贪心,DP+优化)

BZOJ1044: [HAOI2008]木棍分割

bzoj1044[HAOI2008]木棍分割 二分+dp