木棒切割
题意
有n个木棒,最多能切m下,接下来n行,给出n个木棒的长度,求出切割后最大长度的最小值,并求出有多少种切割方式,取模10007
n<=50000,0<=m<=min(n-1,1000),1<=Li<=1000
思路
二分答案,low=0,high=sum[n]。
得到最小值ans。
接下来用DP,求出切割种数。
dp[i][j]表示前i个木棒切割j下的种数,设sum[i] 是前i个木棒的长度和 ,那么dp[i][j]=求和{ dp[k][j-1] },满足条件:k<i && sum[i] - sum[k]<=ans 。
但是写完之后,我们发现,诶,这个时间复杂度……O(n^2 * m),这不超时有鬼……
于是我们可以进行下面的优化:
1、空间
由于当前的dp[][j]只与dp[][j-1]有关,所以呢,我们可以用滚动数组,用dp[][now]代替dp[i][j],用dp[][pre]代替dp[][j-1],其中pre=now^1。
这样空间就小啦~
2、时间
这个好难理解啊我觉得……大概是太笨了哼唧
对于dp[i][now],其实是dp[Mink][pre]……dp[i-1][Mink]的和!!Mink 就是满足 k<i && sum[i]-sum[k]<=ans的最小的k。那么,对于从 1 到 n 枚举的 i ,相对应的 Mink 也一定是非递减的(因为 Sum[i] 是递增的)。我们记录下 dp[1][pre]…dp[i-1][pre] 的和 S ,Mink 初始设为 1,每次对于 i 将 Mink 向后推移,推移的同时将被舍弃的 p 对应的 dp[p][pre] 从 S 中减去。那么 dp[i][Now] 就是 S 的值。
时间复杂度O(nm)。
看!代码
1 |
|