[BZOJ1233][Usaco2009Open]干草堆tower
Description
奶牛们讨厌黑暗。 为了调整牛棚顶的电灯的亮度,Bessie必须建一座干草堆使得她能够爬上去够到灯泡 。一共有N大包的干草(1<=N<=100000)(从1到N编号)依靠传送带连续的传输进牛棚来。第i包干草有一个 宽度W_i(1<=w_i<=10000)。所有的干草包的厚度和高度都为1. Bessie必须利用所有N包干草来建立起干草堆,并且按照他们进牛棚的顺序摆放。她可以相放多少包就放 多少包来建立起tower的地基(当然是紧紧的放在一行中)。接下来他可以放置下一个草包放在之前一级 的上方来建立新的一级。注意:每一级不能比下面的一级宽。她持续的这么放置,直到所有的草包都被安 置完成。她必须按顺序堆放,按照草包进入牛棚的顺序。说得更清楚一些:一旦她将一个草包放在第二级 ,她不能将接下来的草包放在地基上。 Bessie的目标是建立起最高的草包堆。
Input
第1行:一个单一的整数N。 第2~N+1行:一个单一的整数:W_i。
Output
第一行:一个单一的整数,表示Bessie可以建立的草包堆的最高高度。
Sample Input
1
2
3
Sample Output
2
输出说明:
前两个(宽度为1和2的)放在底层,总宽度为3,在第二层放置宽度为3的。
+----------+
| 3 |
+---+------+
| 1 | 2 |
+---+------+
这怕不是考过...考试题然后翻过来?问问问...
翻译一下题目,就是在一段序列里,尽可能多的划分出一些子区间,使得这些区间的长度单调不升。
于是反过来,我们从n往1加,使得这些区间单调不降。
于是,设f[i]为到第i块干草,所能达到的最大高度, g[i]为f[i]最优时最后一块的最小长度。
所以f[i] = f[j] + 1 (sum[i] - sum[j] >= g[j])(i+1<=j<=n+1), sum是后缀和。
如果上面的式子可以更新,那么g[i] = min(g[i], sum[i] - sum[j]);
发现这样转移是n^2的,数据范围卡着不让过。
所以我们优化一下。
观察到的sum值对于i递减是递增的,所以对于上面的式子i往左移动, 它的j要么是不动,要么是往左移动。
就从i+1开始扫到n+1,如果有可以更新的就更新然后退出。
最后答案就是f[1]
#include <iostream> #include <cstdio> #include <cstring> using namespace std; inline int read(){ int res = 0;char ch=getchar(); while(!isdigit(ch))ch=getchar(); while(isdigit(ch)){res=(res<<3)+(res<<1)+(ch^48);ch=getchar();} return res; } int n; int a[200005]; long long qzh[200005]; int f[200005]; long long g[200005]; int main() { n = read(); for (register int i = 1 ; i <= n ; i ++) a[i] = read(); for (int i = n ; i >= 1 ; i --) qzh[i] = qzh[i+1] + a[i]; memset(g, 0x3f, sizeof g); g[n+1] = 0; for (register int i = n ; i >= 1 ; i--) { for (register int j = i + 1 ; j <= n + 1 ; j ++) { if (qzh[i] - qzh[j] >= g[j]) { if (f[j] + 1 > f[i]) { f[i] = f[j] + 1; g[i] = min(g[i], qzh[i] - qzh[j]); break; } } } } cout << f[1]; return 0; }
$\sum_{age=16}^{18} hardworking = success$