zoukankan      html  css  js  c++  java
  • 【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] - Sum[k] <= Len))  

      这样的空间复杂度为 O(nm) ,时间复杂度为 O(n^2 m) 。显然都超出了限制。

      下面我们考虑 DP 的优化。

      1) 对于空间的优化。

        这个比较显然,由于当前的 f[][j] 只与 f[][j-1] 有关,所以可以用滚动数组来实现。

        f[i][Now] 代替了 f[i][j] , f[i][Now^1] 代替了 f[i][j-1] 。为了方便,我们把 f[][Now^1] 叫做 f[][Last] 。

        这样空间复杂度为 O(n) 。满足空间限制。

      2) 对于时间的优化。

        考虑优化状态转移的过程。

        对于 f[i][Now] ,其实是 f[mink][Last]...f[i-1][Last] 这一段 f[k][Last] 的和,mink 是满足 Sum[i] - Sum[k] <= Len 的最小的 k ,那么,对于从 1 到 n 枚举的 i ,相对应的 mink 也一定是非递减的(因为 Sum[i] 是递增的)。我们记录下 f[1][Last]...f[i-1][Last] 的和 Sumf ,mink 初始设为 1,每次对于 i 将 mink 向后推移,推移的同时将被舍弃的 p 对应的 f[p][Last] 从 Sumf 中减去。那么 f[i][Now] 就是 Sumf 的值。

        这样时间复杂度为 O(nm) 。满足时间限制。

     1 /**************************************************************
     2     Problem: 1044
     3     User: Tunix
     4     Language: C++
     5     Result: Accepted
     6     Time:4152 ms
     7     Memory:4396 kb
     8 ****************************************************************/
     9  
    10 //BZOJ 1044
    11 #include<vector>
    12 #include<cstdio>
    13 #include<cstring>
    14 #include<cstdlib>
    15 #include<iostream>
    16 #include<algorithm>
    17 #define rep(i,n) for(int i=0;i<n;++i)
    18 #define F(i,j,n) for(int i=j;i<=n;++i)
    19 #define D(i,j,n) for(int i=j;i>=n;--i)
    20 #define pb push_back
    21 using namespace std;
    22 inline int getint(){
    23     int v=0,sign=1; char ch=getchar();
    24     while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();}
    25     while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();}
    26     return v*sign;
    27 }
    28 const int N=1e5+10,INF=~0u>>2,P=10007;
    29 typedef long long LL;
    30 /******************tamplate*********************/
    31 int n,m,ans,a[N],f[N][2],pos[N],sumf[N][2];
    32 LL s[N];
    33 bool check(int len){
    34     int cnt=0,sum=0;
    35     F(i,1,n){
    36         if (a[i]>len) return 0;
    37         if (sum+a[i]>len){
    38             cnt++; sum=a[i];
    39         }else sum+=a[i];
    40     }
    41     return cnt<=m;
    42 }
    43 int main(){
    44 #ifndef ONLINE_JUDGE
    45     freopen("1044.in","r",stdin);
    46     freopen("1044.out","w",stdout);
    47 #endif
    48     n=getint(); m=getint();
    49     F(i,1,n) {a[i]=getint();s[i]=s[i-1]+a[i];}
    50      
    51     int l=0,r=s[n],mid;
    52     while(l<=r){
    53         mid=l+r>>1;
    54         if (check(mid)) ans=mid,r=mid-1;
    55         else l=mid+1;
    56     }
    57     printf("%d ",ans);
    58     F(i,0,n) sumf[i][0]=1;
    59     int way=0;
    60     F(j,1,m+1){
    61         int now=j&1; 
    62         sumf[0][now]=0;
    63         F(i,1,n){
    64             if (!pos[i]) 
    65                 pos[i]=pos[i-1]; while(s[i]-s[pos[i]]>ans) pos[i]++;
    66             f[i][now]=(sumf[i-1][now^1]-sumf[pos[i]-1][now^1]+P)%P;
    67             sumf[i][now]=(sumf[i-1][now]+f[i][now])%P;
    68         }
    69         way=(way+f[n][now])%P;
    70     }
    71     printf("%d
    ",way);
    72     return 0;
    73 }
    View Code

    1044: [HAOI2008]木棍分割

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 2008  Solved: 725
    [Submit][Status][Discuss]

    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

    [Submit][Status][Discuss]
  • 相关阅读:
    web设计师和前端设计师的互动—前端工程师应该具备的三种思维
    PyQt入门系列(一):Hello World
    PIL在windwos系统下Image.show无法显示图片问题的解决方法
    大赛学习笔记
    ArcGIS Add-in开发(一)--获取选定要素的属性值
    【转】WPF颜色相关操作
    斗地主小代码
    MAVEN配置私服仓库
    Error creating bean with name 'transactionManager' defined in ServletContext resource XXX
    org.hibernate.HibernateException: getFlushMode is not valid without active transaction
  • 原文地址:https://www.cnblogs.com/Tunix/p/4429655.html
Copyright © 2011-2022 走看看