首页 > 代码库 > 哈尔滨理工大学2016新生赛B题

哈尔滨理工大学2016新生赛B题

做为长城上的卫士,影踪派一直守在螳螂高原上防止螳螂人卡拉克西的入侵。影踪派的长城可以近似看做是一条直线上依次编号为1~N的N个基地组成,编号相邻的两个基地之间由长城相连接,而影踪派掌门祝踏岚所在的影踪禅院位于编号为1的基地。
    祝踏岚发现,每次螳螂人只会选择长城上的一个基地进行猛烈的攻击,所以,祝踏岚每次都要从影踪禅院赶到被攻击的基地亲临前线指挥战斗。但是,在长城上移动是很耗时的,为了能更快的赶到任何一个可能被攻击的基地,祝踏岚决定修建一对传送门。
    一对传送门由两个入口组成,它能实现在两个入口间的瞬间转移。出于安全考虑,这两个入口一定要建造在基地上。祝踏岚想选出两个合适的基地建造这一对传送门,使得他从影踪禅院赶到任何一个基地所需要的移动距离最远的那个最短。(每次祝踏岚都会选择采用最短的方式前往每一个基地)。你能帮助他么?

 

第一行为一个正整数T,表示测试数据组数。

每组测试数据第一行为一个整数N(1 <= N <= 100000),第二行包含N-1个正整数,其中第i个数表示编号为i的基地与编号为i+1的基地之间的长城长度。此长度不会超过2147483647.

 

对每组测试数据输出一行,仅含一个整数,表示按照最优方案建造完虫洞后,祝踏岚需要从基地1赶到的移动距离最远的基地的移动距离。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;

const int maxn = 1100000;
int i, j, r, n, m, ansi, ansj, ansr;
long long ans;
long long p[maxn];

inline void make() {
    long long temp;
    ans = p[n];
    i = j = 1;
    while (i <= n) {
        while (j < i && p[j] <= p[i] - p[j])
            j++;
        temp = max(p[i] - p[j], p[j-1]);
        temp = max(p[n] - p[i], temp);
        if (temp < ans) {
            ans = temp;
            ansi = i;
            ansj = j;
        }
        i++;
    }
}

int main()
{
    int T;
    scanf("%d", &T);
    while (T--) {
        memset(p, 0, sizeof(p));
        scanf("%d", &n);
        for (i = 2; i <= n; i++) {
            scanf("%lld", &p[i]);
            p[i] += p[i-1];
        }
        make();
        printf("%lld\n", ans);
    }
    return 0;
}

  

对于任意点K,其与点1之间的最短路有两种情况:

(1)   直接从点1走到K;

(2)   从1走到点A,通过A直接跳到点B,再从B走到K。

或者说,这条最短路等于min(直接从1走到K的距离,从1走到点A通过A跳到B在从B走到K的距离)。

设点I和J之间的直线距离为DIS[I,J],则:

在第(1)种情况下,最短路长度为DIS[1,K];

在第(2)种情况下,最短路长度为DIS[1,A] + DIS[B,K];

由于DIS[1,A]是一个常数(因为A固定),而与K有关的只有B,应直接选择A=1使DIS[1,1] = 0.(也就是说传送门的第一个点一定要建在1点上)。

对当前枚举的第二个传送点位置B,必有唯一一个点C具有如下性质:

DIS[1,C] <= DIS[C,K] 且 DIS[1,C+1] > DIS[C,K]

此时距离1最长的点为C,C+1或N中的一个。

留意到随着B的递增,C是不递减的,所以在O(n)枚举B的同时只需要O(1)就可以找到C。

哈尔滨理工大学2016新生赛B题