首页 > 代码库 > 洛谷P1848 [USACO12OPEN]书架Bookshelf

洛谷P1848 [USACO12OPEN]书架Bookshelf

当农夫约翰闲的没事干的时候,他喜欢坐下来看书。多年过去,他已经收集了 N 本书 (1 <= N <= 100,000), 他想造一个新的书架来装所有书。

每本书 i 都有宽度 W(i) 和高度 H(i)。书需要按顺序添加到一组书架上;比如说,第一层架子应该包含书籍1 ... k,第二层架子应该以第k + 1本书开始,以下如此。每层架子的总宽度最大为L(1≤L≤1,000,000,000)。每层的高度等于该层上最高的书的高度,并且整个书架的高度是所有层的高度的总和,因为它们都垂直堆叠。

请帮助农夫约翰计算整个书架的最小可能高度。

有N(1 <= N <= 100000)本书,每本书有一个宽度W(i),高度H(i),(1 <= H(i) <= 1,000,000; 1 <= W(i) <= L)。

现在有足够多的书架,书架宽度最多是L (1 <= L <= 1,000,000,000),把书按顺序(先放1,再放2.....)放入书架。某个书架的高度是该书架中所放的最高的书的高度。

将所有书放入书架后,求所有书架的高度和的最小值?

题目大意:一段元素,每个元素有两个权值h和w,要把它分成若干段(不限制段数),每一段的 $\sum{w}$ 不能超过 L,最终的代价是每段的最大元素之和 $ \sum{max_{h}} $ ,最小化代价

终于过了这个破题
第一次WA因为没判边界条件
第二次WA因为答案爆了int
第三次T了?没关系,进大牛开O2稳过
题解:f[i] 分完i这个数然后pia叽断开的最小高度和
f[i] = min{f[j]+max{h[j+1]..h[i]}} (sum[i]-sum[j]<=L)
我们发现对于一个固定的i,max{h[j+1]..h[i]}随j增大单调不增,f[j]随j增大单调不减
而且对于某一些区间,它们中的 max{h[j+1]..h[i]}是一样的,那么这段区间中的最优决策一定是把这一段区间要么全分到后面,要么全分到前面(暂时不考虑长度太长的情况)
那我们可以对所有的区间维护一下以它们的左边界-1位决策点的答案,最终的最优解一定在这些答案之中
然后考虑后面新增了一个数h[i],如果h[i]>h[j-1],那么j-1所在的那一段区间就没用了(它的最大h被迫上升了),把这一段区间和i这个位置合并,重复向前找区间,直到最大值比h[i]大位置,这是一个典型的单调队列从队尾踢元素的操作
然后考虑从队首踢元素,显然如果一个区间太靠左了,那么这个区间可能会因为sum[i]-sum[j]太大而无法取到
然后按照这个思路从队首删除元素就好了,有的时候是把一整个区间都删掉,有的时候是右移一个区间的左端点,注释应该写得挺清楚了
然后我们怎么维护答案呢?网上有的题解说用一颗平衡树实现,其实没那么烦,因为我们只要支持插入,删除,取最小值,维护一个双堆就行了
然而pq真是慢啊,要是不开O2会T两个点,开了O2是洛谷第2(毕竟堆比平衡树常数小多了),第1是个骗了数据的baka

 

  1 #include <iostream>
  2 #include <cstdlib>
  3 #include <cstdio>
  4 #include <algorithm>
  5 #include <string>
  6 #include <cstring>
  7 #include <cmath>
  8 #include <map>
  9 #include <stack>
 10 #include <set>
 11 #include <vector>
 12 #include <queue>
 13 #include <time.h>
 14 #define eps 1e-7
 15 #define INF 0x3f3f3f3f
 16 #define MOD 1000000007
 17 #define rep0(j,n) for(int j=0;j<n;++j)
 18 #define rep1(j,n) for(int j=1;j<=n;++j)
 19 #define pb push_back
 20 #define set0(n) memset(n,0,sizeof(n))
 21 #define ll long long
 22 #define ull unsigned long long
 23 #define iter(i,v) for(edge *i=head[v];i;i=i->nxt)
 24 #define mp make_pair
 25 #define max(a,b) (a>b?a:b)
 26 #define min(a,b) (a<b?a:b)
 27 #include<functional>
 28 #define print_rumtime printf("Running time:%.3lfs\n",double(clock())/1000.0);
 29 #define TO(j) printf(#j": %d\n",j);
 30 //#define OJ
 31 using namespace std;
 32 const int MAXINT = 100010;
 33 const int MAXNODE = 100010;
 34 const int MAXEDGE = 2 * MAXNODE;
 35 char BUF, *buf;
 36 int read() {
 37     char c = getchar(); int f = 1, x = 0;
 38     while (!isdigit(c)) { if (c == -) f = -1; c = getchar(); }
 39     while (isdigit(c)) { x = x * 10 + c - 0; c = getchar(); }
 40     return f*x;
 41 }
 42 char get_ch() {
 43     char c = getchar();
 44     while (!isalpha(c)) c = getchar();
 45     return c;
 46 }
 47 //------------------- Head Files ----------------------//
 48 pair<int, int> q[MAXINT];
 49 struct pq {
 50     priority_queue<ll,vector<ll>,greater<ll> > q, d;
 51     void del(ll p) {
 52         d.push(p);
 53     }
 54     void push(ll p) {
 55         q.push(p);
 56     }
 57     ll top() {
 58         while (!d.empty() && d.top() == q.top()) q.pop(), d.pop();
 59         return q.top();
 60     }
 61     void pop() {
 62         while (!d.empty() && d.top() == q.top()) q.pop(), d.pop();
 63         q.pop();
 64     }
 65 }ans;
 66 ll f[MAXINT], l,n;
 67 int w[MAXINT], H[MAXINT];
 68 ll sum[MAXINT];
 69 void get_input();
 70 void work();
 71 int main() {
 72     get_input();
 73     work();
 74     return 0;
 75 }
 76 void work() {
 77     pair<int, int> *h, *t;
 78     h = t = q;
 79     *t++ = mp(0, INF);//哨兵元素!
 80     rep1(i, n) {
 81         int p = i;
 82         while ((t - 1)->second<H[i]) {
 83             ans.del((t - 1)->second + f[(t - 1)->first - 1]);
 84             p = (t - 1)->first;
 85             t--;
 86         }
 87         *t++ = mp(p, H[i]);
 88         ans.push(f[p - 1] + H[i]);
 89         h++;
 90         while ( (h + 1<t) && sum[i] - sum[(h + 1)->first - 1]>l) ans.del(h->second + f[h->first - 1]), h++; //delete the whole segment
 91         ans.del(h->second + f[h->first - 1]);
 92         for (; sum[i] - sum[h->first-1]>l; h->first++);//delete some element
 93         if ((h+1<t)&&h->first == (h + 1)->first) h++;
 94         else ans.push(h->second + f[h->first - 1]);
 95         h--;
 96         *h = mp(0, INF);
 97         f[i] = ans.top();
 98     }
 99     printf("%lld\n", f[n]);
100 }
101 void get_input() {
102     n = read(); l = read();
103     rep1(i, n) H[i] = read(), w[i] = read(), sum[i] = sum[i - 1] + w[i];
104 }

 

洛谷P1848 [USACO12OPEN]书架Bookshelf