原题链接
题意:有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且输出有多少种砍的方法使得总长度最大的一段长度最小. 并将结果mod 10007。
数据范围
n<=50000, 0<=m<=min(n-1,1000).
1<=Li<=1000
思路:第一问二分答案即可求得,不再赘述。第一问答案为x。
对于第二问,显然这是求方案数的DP。定义状态f[i][j]表示在第i个连接点及其以后的木棍中总共砍j刀的方案数,则有f[i][j]=sum{f[k][j-1],k>i且i至k之间木棍长度之和<=x} 。如果暴力转移,肯定超时。想象有一个长为x的滑动窗口在木棍上方滑动,它的左端点为当前计算的点i,设它覆盖的点集为A,那么f[i][j]=sum{f[k][j-1],k∈A且k>i}。我们从右至左递推时,让滑动窗口的左端点也往左滑动至当前考虑的点,注意到右端点也是单调递减的,此时我们修改右端点,并且删除离开了滑动窗口的点。最终答案为sum{f[0][i],i∈[0,m]}。
ps:递推时要使用滚动数组,否则MLE。
实现细节见代码。
#include<iostream>