zoukankan      html  css  js  c++  java
  • bzoj1044[HAOI2008]木棍分割 单调队列优化dp

    1044: [HAOI2008]木棍分割

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

    第一问二分答案
    第二问dp

    f[i][j]表示前i个木棍切j刀的方案,sum[i]表示前缀和
    f[i][j]+=f[k][j-1] (sum[i]-sum[k]<=ans1)
    这个东西是n^2 * m 的时间 n*m的空间 绝壁炸了

    空间不成问题,直接一个滚动数组
    时间优化,可以发现k一定是连续的一段且有单调性啊。。
    一个单调队列维护转移

     1 #include<bits/stdc++.h>
     2 #define mod 10007
     3 #define N 50005
     4 using namespace std;
     5 int n,m,now,ff,ans,pre,sum[N],a[N],f[N][2];
     6 inline bool check(int x){
     7     int cnt=0,now=0;
     8     for(int i=1;i<=n;i++){
     9         if(a[i]>x)return 0;
    10         if((now+=a[i])<=x)continue;
    11         now=a[i];cnt++;
    12     }
    13     return cnt<=m;
    14 }
    15 int main(){
    16     scanf("%d%d",&n,&m);
    17     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    18     int l=1,r=50000000;
    19     while(l<=r){
    20         int mid=(l+r)>>1;
    21         if(check(mid))r=(ans=mid)-1;
    22         else l=mid+1;
    23     }
    24     printf("%d ",ans);
    25     for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i];
    26     for(register int i=0;i<=m;++i){
    27         pre=now;now^=1;
    28         int res=0,p=1;
    29         for(register int j=1;j<=n;++j){
    30             if(i==0){
    31                 if(sum[j]<=ans)f[j][now]=1;
    32                 else f[j][now]=0; 
    33             }
    34             else{
    35                 while(p<j&&sum[j]-sum[p]>ans)
    36                 res=(res-f[p++][pre])%mod;
    37                 f[j][now]=res;
    38                 res=(f[j][pre]+res)%mod;
    39             }
    40         }
    41         ff=(ff+f[n][now])%mod;
    42     }
    43     ff<0?ff+=mod:1;printf("%d
    ",ff);
    44     return 0;
    45 }
  • 相关阅读:
    在Centos 7下编译openwrt+njit-client
    开博随笔
    Chapter 6. Statements
    Chapter 4. Arrays and Pointers
    Chapter 3. Library Types
    Chapter 2.  Variables and Basic Types
    关于stm32不常用的中断,如何添加, 比如timer10 timer11等
    keil 报错 expected an identifier
    案例分析 串口的地不要接到电源上 会烧掉
    案例分析 CAN OPEN 调试记录 进度
  • 原文地址:https://www.cnblogs.com/wsy01/p/8324575.html
Copyright © 2011-2022 走看看