zoukankan      html  css  js  c++  java
  • 【bzoj1044】[HAOI2008]木棍分割 二分+dp

    题目描述

    有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且输出有多少种砍的方法使得总长度最大的一段长度最小. 并将结果mod 10007。。。

    输入

    输入文件第一行有2个数n,m.接下来n行每行一个正整数Li,表示第i根木棍的长度.n<=50000,0<=m<=min(n-1,1000),1<=Li<=1000.

    输出

    输出有2个数, 第一个数是总长度最大的一段的长度最小值, 第二个数是有多少种砍的方法使得满足条件.

    样例输入

    3 2
    1
    1
    10

    样例输出

    10 2


    题解

    二分+dp

    第一问即 noip2015跳石头 。。。一眼二分,然后看不满足条件时就切一刀,判断是否小于m。

    第二问求方案数,很显然是个dp。

    设$f[i][j]$表示前$i$个分了$j$段的方案数,那么状态转移方程应该为$f[i][j]=sumlimits_{len(t+1,i)le ans1}f[t][j-1]$,边界条件$f[0][0]=1$,其中$len(a,b)表示$[a,b]$所有木棍的长度总和。

    可以发现$t$的取值范围是一段连续的单调的区间,因此可以用类似双指针的方法扫出$t$的取值左端点。然后$sum$又可以使用前缀和维护,这样时间复杂度就降为了$O(nm)$。

    然而这样还会炸空间。。。

    因此使用滚动数组就好了,显然第二维是可以滚动的,因此先枚举第二维,滚动一下就好了。

    #include <cstdio>
    #include <algorithm>
    #define N 50010
    #define mod 10007
    using namespace std;
    int n , m , a[N] , sl[N] , f[2][N] , sum[2][N];
    bool judge(int mid)
    {
    	int i , now = 0 , cnt = 0;
    	for(i = 1 ; i <= n ; i ++ )
    	{
    		if(now + a[i] > mid) now = 0 , cnt ++ ;
    		now += a[i];
    	}
    	return cnt <= m;
    }
    int main()
    {
    	int i , j , l = 0 , r = 0 , mid , ans = -1 , p = 0 , ret = 0 , d;
    	scanf("%d%d" , &n , &m);
    	for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &a[i]) , l = max(l , a[i]) , r += a[i] , sl[i] = sl[i - 1] + a[i];
    	while(l <= r)
    	{
    		mid = (l + r) >> 1;
    		if(judge(mid)) ans = mid , r = mid - 1;
    		else l = mid + 1;
    	}
    	printf("%d " , ans);
    	for(i = 0 ; i <= n ; i ++ ) sum[0][i] = 1;
    	for(i = d = 1 ; i <= m + 1 ; i ++ , d ^= 1)
    	{
    		sum[d][0] = p = 0;
    		for(j = 1 ; j <= n ; j ++ )
    		{
    			while(sl[j] - sl[p] > ans) p ++ ;
    			f[d][j] = sum[d ^ 1][j - 1];
    			if(p) f[d][j] = (f[d][j] - sum[d ^ 1][p - 1] + mod) % mod;
    			sum[d][j] = (sum[d][j - 1] + f[d][j]) % mod;
    		}
    		ret = (ret + f[d][n]) % mod;
    	}
    	printf("%d
    " , ret);
    	return 0;
    }
    

     

  • 相关阅读:
    HDU 5528 Count a * b 欧拉函数
    HDU 5534 Partial Tree 完全背包
    HDU 5536 Chip Factory Trie
    HDU 5510 Bazinga KMP
    HDU 4821 String 字符串哈希
    HDU 4814 Golden Radio Base 模拟
    LA 6538 Dinner Coming Soon DP
    HDU 4781 Assignment For Princess 构造
    LA 7056 Colorful Toy Polya定理
    LA 6540 Fibonacci Tree
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7491510.html
Copyright © 2011-2022 走看看