topcoder SRM 647 解题报告

Div2 1000pts

题意:

有一排房子,标号1~N,每个房子有一个高度,第1栋房子高度为0。有一些限制条件:1每栋房子和他旁边两栋(1和N一栋)的高度差的绝对值小于等于K,2对于一些房子x[i],高度不能超过t[i]。求最高的房子最高可以有多高。

数据范围:

N will be between 1 and 1,000,000,000, inclusive.
K will be between 1 and 1,000,000,000, inclusive.
x will contain between 0 and min(N,500) elements, inclusive.
t will have exactly the same number of elements as x
Each element of x will be between 1 and N, inclusive.
x[i] < x[i+1] for all valid i.
Each element of t will be between 1 and 1,000,000,000, inclusive.

思路:

首先想到的是最高的房子的高度肯定是在两栋有限制maxHeight的房子之间得到的,先不断地变高,达到最高点之后再变矮来满足后面那栋房子的限制条件。所以只要把每个间隔都找一遍,就能得到答案了。

但是这样做会有一些问题,即一栋房子的限制高度可能无法被达到。所以在找间隔之前先更新一遍高度限制,保证相邻两个有限制高度的房子如果高度取最大,也是不矛盾的。

最后对于两栋房子之间的最大高度怎么做有一些细节。对于x和y,先做del步(一步相当于从一栋房子的高度得出下一个房子的高度),每次增加或减少高度K,从HeightX走到小于等于HeightY且和Height高度差小于K。然后假设剩余步数为remStep,remStep为奇数和偶数时可以得到的最大高度是不一样的,WA了好几发,具体看图和代码。
这里写图片描述
代码:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll INF = 1e18+10;
const ll NN = 510;

class BuildingTowers {
public:
    long long maxHeight( int N, int K, vector <int> x, vector <int> t ) ;
};
long long BuildingTowers::maxHeight(int N, int K, vector <int> x, vector <int> t) {
    ll k = K, m = x.size(), a[NN], b[NN], ans = 0;
    for (ll i = 0; i < m; i++)
        a[i+1] = x[i], b[i+1] = t[i];
    a[0] = 1; b[0] = 0;
    for (ll i = m-1; i >= 1; i--)
        b[i] = min(b[i], b[i+1]+(a[i+1]-a[i])*k);
    for (ll i = 1; i <= m; i++)
        b[i] = min(b[i], b[i-1]+(a[i]-a[i-1])*k);
    a[++m] = N; b[m] = b[m-1]+(a[m]-a[m-1])*k;
    for (ll i = 1; i <= m; i++){
        ll delh = b[i]-b[i-1];
        ll del = delh/k;//del的正负表示高度增加还是减少
        if (del*k > delh) del--;
        ll rem = a[i]-a[i-1]-abs(del);
        //rem is even
        if (rem%2 == 0) ans = max(ans, b[i-1]+(max(0ll, del)+rem/2)*k);
        //rem is odd
        else ans = max(ans, b[i]+(max(0ll, -del)+rem/2)*k);
    }
    return ans;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值