标签:
首先这题的n^3的DP是比较好想的
f[i][j]表示用前i包干草 且最顶层为第j+1包到第i包 所能达到的最大高度
然而数据范围还是太大了 因此我们需要去想一想有没有什么单调性
----------------------------------------------------------------------------------------------------
从其他人的题解中 可以看到一个结论 我们尽量使底层最短 便可逐渐达到最优解
然后再结合递推的思想去做 我们就会使在底层最短的基础上使第二层最短 以此类推……
然而根据这个结论 我还是没有什么明确的实现思路 不过忽然想到了这样一组数据
3
2 1 4
我们会发现 仅用前两包 可以达到2的高度 然而加上第3包后 反而只能达到1的高度了
可是如果倒着推的话 情况就大不一样了 因为多的部分直接堆在底层就好了
所以倒着推所得到的答案是单调的
这样的话 我们又可以用 f[i]记录以i到n包做草堆 底层的最小长度 g[i]记录此时能达到的最大高度
这样就优化到n^2了
----------------------------------------------------------------------------------------------------
接下来 我们再观察一下递推式
f[i]=min(sum[j-1]-sum[i-1]),j>i&&f[j]<=sum[j-1]-sum[i-1]
显然f[i]从较小的j转移过来结果会更优(如果符合转移条件的话) (*)
而对于转移条件 f[j]<=sum[j-1]-sum[i-1] 我们把式子移项得到 sum[i-1]<=sum[j-1]-f[j]
这样的话 对于决策j 显然sum[j-1]-f[j]越大 可以作为决策的情况就越多 而根据(*) 我们知道j越小越好
因此如果存在决策k>j 满足 sum[k-i]-f[k]>=sum[j-1]-f[j] 那么决策k便一定不能用上
于是这个问题就转变为了用单调队列来维护单调性DP的经典模型了
----------------------------------------------------------------------------------------------------
具体实现可参考代码(然而如果把上面的内容认真读了还不会自己实现的话……)
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #define rep(i,n) for(int i=1;i<=n;++i) #define imax(x,y) (x>y?x:y) #define imin(x,y) (x<y?x:y) using namespace std; const int N=100010; int sum[N],f[N],g[N],q[N]; int n; int main() { scanf("%d",&n); rep(i,n) { scanf("%d",&sum[i]); sum[i]+=sum[i-1]; } int ifront=1,itail=1; q[1]=n+1; for(int i=n;i;--i) { while(ifront<itail&&sum[q[ifront+1]-1]-sum[i-1]>=f[q[ifront+1]]) ++ifront; f[i]=sum[q[ifront]-1]-sum[i-1]; g[i]=g[q[ifront]]+1; while(ifront<=itail&&sum[q[itail]-1]-f[q[itail]]<=sum[i-1]-f[i])--itail; q[++itail]=i; } printf("%d",g[1]); return 0; }
bzoj 1233: [Usaco2009Open]干草堆tower 【想法题】
标签:
原文地址:http://www.cnblogs.com/sagitta/p/4650681.html