• [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
    O(∩_∩)O~ (*^__^*) 嘻嘻…… O(∩_∩)O哈哈~
  • 相关阅读:
    linux报错jar包时出现“Exception in thread "main" java.lang.SecurityException: Invalid signature file digest for Manifest main attributes”
    重写ajax方法实现请求session过期时跳转登录页面
    C++学习之NVI
    C++学习之Pimpl
    C++学习之allocator
    C++ 强制类型转换
    C++中的volatile关键字
    C++强大背后
    C++学习之智能指针
    C++学习之异常
  • 原文地址:https://www.cnblogs.com/wls001/p/7682975.html
Copyright © 2020-2023  润新知