【51Nod三级题】玻璃切割

链接:
题意:
现在有一块玻璃,是长方形的(w 毫米× h 毫米),现在要对他进行切割。
切割的方向有两种,横向和纵向。每一次切割之后就会有若干块玻璃被分成两块更小的玻璃。在切割之后玻璃不会被移动。
现在想知道每次切割之后面积最大的一块玻璃是多少。
样例解释:
对于第四次切割,下面四块玻璃的面积是一样大的。都是2。
输入样例
4 3 4
H 2
V 2
V 3
V 1
输出样例
8
4
4
2
思路:
这道题的思路不是很难,关键是编码,很考验编码能力,我从构思到通过,想到了3种方法,但是最后都发现不好编码放弃了,最后想了个版本,通过了,在51nod效率榜上居然是第3。
说一下我的思路吧,处理方法就是先按步骤划分,然后从尾到头,将玻璃合并,在合并过程中维护玻璃的最大值。
关键是编码,我用了结构体,有is_cut,l,r三个字段,横和纵分别处理,在划分过程中,除了标记 is_cut以外,就是算出l和r的值,它们表示当前划分处离它们左右两个划分处的距离,当它们算出来后。
在合并的时候就很方便了,比如横向上要合并x这个位置,那么x.l+x.r就是合并后的新距离,只要把这个新距离赋值给x划分处的前后两个划分处的l和r就行了,也就是[x+x.l].r=x.l+x.r,[x-x.r].l=x.l+x.r。
这种处理方法无论在时间复杂度还有空间复杂度上都是很不错的。
AC代码:
#include<bits/stdc++.h>  
#define ll long long  
#define endl "\n"  
const int N=2e5+5;  
const int INF=0x3f3f3f3f;  
const int MOD=1e9+7;  
const double eps=1e-6;  
using namespace std;  
struct A{  
    ll l,r;  
    bool is_cut;  
}W[N],H[N];  
int w,h,n,x;  
char c;  
  
void run(){  
    cin>>w>>h>>n;  
    W[w].is_cut=true,H[h].is_cut=true;  
    vector<pair<char,int>> re;  
    while(n--){  
        cin>>c>>x;  
        re.push_back({c,x});  
        if(c=='H') H[x].is_cut=true;   //横向切割-》h  
        else W[x].is_cut=true; //-》w  
    }  
    ll mavH=-1,mavW=-1,cur=0,res=-1;  
    for(int i=1;i<=h;++i) if(H[i].is_cut) H[i].r=i-cur,mavH=max(mavH,i-cur),cur=i;  
    cur=h;  
    for(int i=h-1;i>=1;--i) if(H[i].is_cut) H[i].l=cur-i,cur=i;  
    cur=0;  
    for(int i=0;i<=w;++i) if(W[i].is_cut) W[i].r=i-cur,mavW=max(mavW,i-cur),cur=i;  
    cur=w;  
    for(int i=w-1;i>=1;--i) if(W[i].is_cut) W[i].l=cur-i,cur=i;  
    res=max(res,mavH*mavW);  
    vector<ll> ans;  
    ans.push_back(res);  
    reverse(re.begin(),re.end());  
    re.pop_back();  
    for(auto each:re){  
        if(each.first=='H'){  
            ll len=H[each.second].l+H[each.second].r;  
            H[each.second+H[each.second].l].r=len;  
            H[each.second-H[each.second].r].l=len;  
            mavH=max(mavH,len);  
        }else{  
            ll len=W[each.second].l+W[each.second].r;  
            W[each.second+W[each.second].l].r=len;  
            W[each.second-W[each.second].r].l=len;  
            mavW=max(mavW,len);  
        }  
        res=max(res,mavH*mavW);  
        ans.push_back(res);  
    }  
    reverse(ans.begin(),ans.end());  
    for(auto each:ans) cout<<each<<endl;  
}  
  
int main(){  
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);  
    freopen("../input.txt","r",stdin);  
    freopen("../output.txt","w",stdout);  
    int _=1;  
    //cin>>_;  
    for(int i=0;i<_;++i) run();  
    return 0;  
}  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

~Lomiss~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值