• BZOJ 1044 HAOI2008 木棍分割


    1044: [HAOI2008]木棍分割
    
    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 4241  Solved: 1627
    [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
    2                           
    
    
    Sample Output
    2
    HINT
    
    两种砍的方法: (1)(1)(10)和(1 1)(10)
    第一问很显然二分+贪心
    第二问也很显然是一个dp
    但是裸的dp复杂度应该是n^2m的
    f[i][j]表示枚举到i切了刀并且不超过最大长度的方案数
    f[i][j]=sigmaf[k][j-1] (mink<k<i-1) mink表示k最小取到的数
    那么sum[i]-sum[k]<=MAXNLEN
    我们要考虑怎么省去一维n,我们想到前缀和是单调递增的
    所以随着我们枚举i最小符合的前缀的下标也是单调递增的,我们可以去维护
    f[mink]~f[i-1]的和sumf,如果mink不符合的话就减去,算完后再把f[i][j-1]
    加到sumf中
     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 inline int read(){
     4     int x=0;int f=1;char ch=getchar();
     5     while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
     6     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
     7     return x*f;
     8 }
     9 const int MAXN=1e6+10;
    10 const int mod=10007;
    11 int f[3][MAXN]={},n,m,a[MAXN],sum[MAXN];
    12 inline bool check(int xx){
    13     int sum=0;
    14     int summ=0;
    15     for(int i=1;i<=n;i++){
    16         if(a[i]>xx) return 0;
    17         sum+=a[i];
    18         if(sum>xx){
    19             sum=a[i];summ++;
    20         }
    21     }
    22     return summ<=m;
    23 }
    24 inline int  erfen(){
    25     int leftt=1;int rightt=100000017;
    26     while(leftt+1<rightt){
    27         int mid=(rightt+leftt)>>1;
    28         if(check(mid)) rightt=mid;
    29         else leftt=mid;
    30     }
    31     if(check(leftt)) return leftt;
    32     else return rightt;
    33 } 
    34 void init(){
    35     n=read();m=read();
    36     for(int i=1;i<=n;i++){
    37         a[i]=read();
    38         sum[i]=sum[i-1]+a[i];
    39     }
    40 }
    41 void dp(){
    42     int k=erfen();
    43     cout<<k<<' ';
    44     int cnt=1;
    45     int ans=0;
    46     for(int i=0;i<=m;i++){
    47         int sumf=0;int mink=0;//sumf表示f的总和 
    48         for(int j=1;j<=n;j++){
    49             if(i==0){
    50                 if(sum[j]<=k) f[cnt][j]=1;
    51                 else f[cnt][j]=0;
    52             }
    53             else{
    54                 while(sum[j]-sum[mink]>k){
    55                     sumf-=f[cnt^1][mink];
    56                     sumf=(sumf+mod)%mod;
    57                     mink++;
    58                 }
    59                 f[cnt][j]=sumf;
    60                 f[cnt][j]%=mod;
    61                 sumf+=f[cnt^1][j];
    62                 sumf%=mod;
    63             }
    64         }
    65         ans+=f[cnt][n];
    66         ans%=mod;
    67         cnt^=1;    
    68     }
    69     cout<<ans<<endl;
    70 }
    71 int main(){
    72     //freopen("All.in","r",stdin);
    73     //freopen("a.out","w",stdout);
    74     init();
    75     dp();
    76     return 0;
    77 }
    78 
    79 代码
    代码
  • 相关阅读:
    Nancy学习
    微信公众号开发开发问题记-code been used
    C#——委托、Lambda表达式、闭包和内存泄漏
    【协作式原创】查漏补缺之Go的slice基础和几个难点
    【协作式原创】自己动手写docker之run代码解析
    【算法】剑指第二版3.数组中重复数字
    剑指offer第二版速查表
    【协作式原创】查漏补缺之乐观锁与悲观锁TODO
    【协作式原创】查漏补缺之Go并发问题(单核多核)
    【协作式原创】查漏补缺之Golang中mutex源码实现(预备知识)
  • 原文地址:https://www.cnblogs.com/something-for-nothing/p/7857290.html
Copyright © 2020-2023  润新知