[HackerRank 101 Hack 51] Small Cubes

来源:互联网 发布:iphone8知乎 编辑:程序博客网 时间:2024/06/10 00:45

题意

给定一个(n,m,k)的长方体,沿x轴每一层mk个单位1的小正方体,其中,每一层都有一个矩形区域是空的,这个矩形区域是平行于y,z轴的。现在用正方体填满这个长方体的空缺部分,用到的正方体的最大边长为max,正方体的个数为num,最大化maxp+numq,p,q给出。n,m,k105

题解

如果确定了max,那么显然边长为max的正方体只用一个,其他区域都用边长为1的填充是更优的。同时,如果一个边长为max的正方体放的进去,max1的正方体肯定也能放的进去。如果能求得max的最大值就可以通过O(n)枚举max来求得答案了。
那么如何求得max的最大值呢?根据max合法的单调性,可以考虑二分。由于n105,应当考虑O(n)的检验使得复杂度为O(nlogn)
如何进行O(n)检验一个数M是否合法呢?一开始我用4个set维护当前区间(区间长度为M)内上下左右的边界进而检验(判断上边界的最小值与下边界最大值之差是否不小于M,左右边界同理),可这样是O(nlogn)的,总复杂度O(nlog2n)但常数不小,T掉了。后来思考,我们只关心当前区间内的最小值或最大值,可以用单调队列O(n)实现,更改一些细节后AC。

代码

/// by ztx/// blog.csdn.net/hzoi_ztx#include <bits/stdc++.h>#define Rep(i,l,r) for(i=(l);i<=(r);i++)#define rep(i,l,r) for(i=(l);i< (r);i++)#define Rev(i,r,l) for(i=(r);i>=(l);i--)#define rev(i,r,l) for(i=(r);i> (l);i--)#define Each(i,v)  for(i=v.begin();i!=v.end();i++)#define r(x)   read(x)typedef long long ll ;typedef double lf ;int CH , NEG ;template <typename TP>inline void read(TP& ret) {    ret = NEG = 0 ; while (CH=getchar() , CH<'!') ;    if (CH == '-') NEG = true , CH = getchar() ;    while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ;    if (NEG) ret = -ret ;}#define  kN  100010LLstruct node {    int val,id;    bool operator < (const node&b)const{ if (val==b.val) return id<b.id; return val<b.val; }};int N, M, K, Q, P;int lef[kN], dow[kN], rig[kN], up[kN];bool ok(int d) {    //std::set<node>su,sd,sl,sr;    std::deque<int>su,sd,sl,sr;    node tmp;    for(int i=1,tu,td,tl,tr;i<=N;i++) {        while (!su.empty()&&up[i]<=up[su.back()]) su.pop_back(); su.push_back(i);        while (!sr.empty()&&rig[i]<=rig[sr.back()]) sr.pop_back(); sr.push_back(i);        while (!sd.empty()&&dow[i]>=dow[sd.back()]) sd.pop_back(); sd.push_back(i);        while (!sl.empty()&&lef[i]>=lef[sl.back()]) sl.pop_back(); sl.push_back(i);        if (i<d) continue;        if (su.front()<=i-d) su.pop_front();        if (sd.front()<=i-d) sd.pop_front();        if (sl.front()<=i-d) sl.pop_front();        if (sr.front()<=i-d) sr.pop_front();        tu = up[su.front()];        tr = rig[sr.front()];        td = dow[sd.front()];        tl = lef[sl.front()];        if (tu-td+1>=d && tr-tl+1>=d) return true;    }    return false;}ll tot, ans, now, num;int main() {    int i,L,R,mid,Max;    r(N), r(M), r(K), r(P), r(Q);    tot=0;    Rep (i,1,N) r(lef[i]), r(dow[i]), r(rig[i]), r(up[i]),tot+=(rig[i]-lef[i]+1LL)*(up[i]-dow[i]+1LL);    L = 1, R = N+1;    while (R-L > 1) { // [L,R)        mid = (L+R)/2;        if (ok(mid)) L=mid;        else R=mid;    }    ans = 0;    Max = L;    Rep (i,1,Max) {        num = tot+1LL-1LL*i*i*i;        now = 1LL*i*P+num*Q;        if (now>ans) ans = now;    }    printf("%lld\n", ans);    END: getchar(), getchar();    return 0;}
原创粉丝点击