zoukankan      html  css  js  c++  java
  • 2017辽宁冬令营-1.摩天大楼

    摩天大楼(dom.pas/c/cpp)
    题目大意
    在数轴上有 N 栋摩天大楼,第 i 栋的位置为 Xi,高度为 Hi,现在你需要推倒所有的摩
    天大楼。你每次可以选择炸毁一个大楼使得它往左边倒下去,或者往右边倒下去,在一栋摩
    天大楼倒下去的时候,有可能顺带推倒了一些其他的摩天大楼。第 i 栋大楼向左倒会将所有
    在它左边并且满足|Xi-Xj|<=Hi 的摩天大楼同时向左推倒,并且这些摩天大楼在倒下去的时
    候有可能带动其他的大楼继续倒下(向右同理) 。
    现在问最少需要炸多少次摩天大楼才能使得所有的摩天大楼均被推倒。
    输入文件
    输入文件为 dom.in。
    第一行一个整数 N,表示摩天大楼的个数。
    以下 N 行每行两个整数 Xi,Hi,表示第 i 栋摩天大楼位置以及它的高度。
    输入保证 Xi 递增输入。
    输出文件
    输出文件为 dom.out。
    输出一行一个整数代表最少炸毁的次数。
    样例输入
    6
    1 1
    2 2
    3 1
    5 1
    6 1
    8 3
    样例输出
    2
    数据规模与约定
    对于 30%的数据,N≤10;
    对于 50%的数据,N≤1000;
    对于 100%的数据,N≤100000,Hi≤10^8,0≤Xi≤2^31。

    ————————————————————————————————题解

    我们求出l[x],r[x]表示把第x座往左推能倒多少座,第x座往右推能推倒多少座

    更新时dp[x+r[x]-1]=min(dp[x-1]+1) (这个要先更新因为先更新l[x]会影响到后面,造成一栋楼往左推和往右推同时更新)

    往左推要找dp[x-l[i]+1]-dp[x-1]中最小的一个,所以要再单调栈上二分

    同理寻找l[x]和r[x]也要找到延伸最远的一个,单调栈上二分

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>//important
     4 #include <algorithm>
     5 #include <vector>
     6 #define siji(i,x,y) for(int i=(x);i<=(y);++i)
     7 #define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
     8 #define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
     9 #define sigongzi(j,x,y) for(int j=(x);j>(y);--j)
    10 #define ivorysi
    11 #define inf 0x7f7f7f7f 
    12 typedef long long ll;
    13 using namespace std;
    14 int l[100005],r[100005],pos[100005],h[100005],dp[100005],n; 
    15 vector<int> st;
    16 int binary(int poi,int on) {
    17     int l=0,r=st.size(),mid;
    18     while(l<r) {
    19         mid=(l+r)/2;
    20         if(on*pos[st[mid]]>=on*poi) r=mid;
    21         else l=mid+1;
    22     }
    23     return r>=st.size() ? -1 : r;
    24 }
    25 void init() {
    26     scanf("%d",&n);
    27     siji(i,1,n) {
    28         scanf("%d%d",&pos[i],&h[i]);
    29     }
    30     pos[0]=-1000000;//寻找1-l[1]时就是-1
    31     st.clear();
    32     siji(i,1,n) {
    33         int x=binary(pos[i]-h[i],1);
    34         if(x!=-1)l[i]=i-st[x]+l[st[x]];
    35         else l[i]=1;
    36         while(st.size()>=1 && 
    37             st[st.size()-1]-l[st[st.size()-1]]>=i-l[i])//不是l[i]越大越好,而是看它往左倒可以延伸到哪里 
    38             st.pop_back();
    39         st.push_back(i);
    40     }
    41     st.clear();
    42     gongzi(i,n,1) {
    43         int x=binary(pos[i]+h[i],-1);
    44         if(x!=-1) r[i]=st[x]-i+r[st[x]];
    45         else r[i]=1;
    46         while(st.size()>=1 && 
    47             st[st.size()-1]+r[st[st.size()-1]]<=i+r[i]) 
    48             st.pop_back();
    49         st.push_back(i);
    50     }
    51     memset(dp,inf,sizeof(dp));
    52     dp[0]=0;
    53 }
    54 void solve() {
    55     init();
    56     st.clear();
    57     st.push_back(0);
    58 
    59     siji(i,1,n) {
    60         dp[i+r[i]-1]=min(dp[i+r[i]-1],dp[i-1]+1);
    61         int x=binary(pos[i-l[i]],1);//找到i-l[i]-1之前的一个最大的,所以寻找pos[i-l[i]]
    62         if(x!=-1) dp[i]=min(dp[i],dp[st[x]]+1);
    63         else dp[i]=min(dp[i],dp[i-1]+1);
    64         while(st.size()>=1 &&
    65             dp[st[st.size()-1]]>=dp[i])
    66             st.pop_back();
    67         st.push_back(i);
    68     }
    69     printf("%d
    ",dp[n]);
    70 }
    71 int main(int argc, char const *argv[]) 
    72 {
    73 #ifdef ivorysi
    74     freopen("dom.in","r",stdin);
    75     freopen("dom.out","w",stdout);
    76 #else
    77     freopen("f1.in","r",stdin);
    78 #endif
    79 
    80     solve();
    81     return 0;
    82 }
  • 相关阅读:
    getContentResolver()内容解析者查询联系人、插入联系人
    ContentProvider备份短信,以xml文件存储
    ContentProvider详解
    bindService初步了解
    Service之来电监听(失败的案例)
    Android帧动画
    AlertDialog之常见对话框(单选对话框、多选对话框、进度条对话框)
    BroadcastReceiver之(手动代码注册广播)屏幕锁屏、解锁监听、开机自启
    BroadcastReceiver之有序广播
    [FJOI2015]火星商店问题
  • 原文地址:https://www.cnblogs.com/ivorysi/p/6395529.html
Copyright © 2011-2022 走看看