hdu5261单调队列

题意特难懂,我看了好多遍,最后还是看讨论版里别人的问答,才搞明白题意,真是汗。

其实题目等价于给n个点,这n个点均匀分布在一个圆上(知道圆半径),点与点之间的路程(弧长)已知,点是有权值的,已知,点与点的距离等于其最短路程(弧长)加上两点的权值,问距离最远的两个点的下标。

因为是环状,不好处理,所以我在输入的时候就简单处理了一下,使问题变成直线上的等价问题了。做法就是在输入序列后面再加上前半段序列,例如样例5 2 1 10 1 10 10,可以处理成1 10 1 10 10 1 10,这样就只需要顺序处理了,不过最后输成的下标是需要处理的,因为要求的是字典序最小的下标对。

变成直线后的问题就比较简单了。便于理解的做法是维护一个长度为半圆的队列,当处理i时,把队列里的点和i点比较,更新最值,然后i入队,队列头元素出队。这是n^2的效率,换成单调队列,就能过了。不过,我是用优先队列做的,代码比用单调队列稍复杂一丁点,也是脑子木了,还没打完,金牛就把我代码要了去用单调队列接着打了。先贴上金牛的单调队列的代码,再贴我的,都是1a:

/*

 * Author : ben

 */

#include <cstdio>

#include <cstdlib>

#include <cstring>

#include <cmath>

#include <ctime>

#include <iostream>

#include <algorithm>

#include <queue>

#include <set>

#include <map>

#include <stack>

#include <string>

#include <vector>

#include <deque>

#include <list>

#include <functional>

#include <numeric>

#include <cctype>

using namespace std;



#define D(x) 



typedef long long LL;

const int MAXN = 200000;



int R, N;

LL m;

int data[MAXN];

LL ans;

int ansi, ansj;



void update(LL a, LL b)

{

    LL temp = (b - a) * R + data[a] + data[b];

    a %= N - m;

    b %= N - m;

    if (a > b)

        swap(a, b);

    if (temp > ans)

    {

    D(printf("a %lld b %lld\n", a, b));

        ans = temp;

        ansi = a;

        ansj = b;

        return;

    }

    if (temp < ans)

        return;

    if (ans == 40)

    if (ansi > a || (ansi == a && ansj > b))

    {

        ansi = a;

        ansj = b;

        return;

    }

}



LL work() {



    deque<LL> q;

    q.push_back(0);

    long long cur_pos = 0;

    long long ret = 0;

    for (int i = 1; i < N; i++)

    {

        cur_pos += R;

        while (!q.empty() && q.front() < i - m)

            q.pop_front();

        update(q.front(), i);

        while (!q.empty() && (i - q.back()) * R + data[q.back()] < data[i])

            q.pop_back();

        q.push_back(i);

    }

    return ret;

}



int main() {

    int T;

    scanf("%d", &T);

    for (int t = 1; t <= T; t++) {

        scanf("%d %d", &N, &R);

        for (int i = 0; i < N; i++) {

            scanf("%d", &data[i]);

        }

        m = N / 2;

        for (int i = 0; i < m; i++) {

            data[i + N] = data[i];

        }

        N += m;

        ans = 0;

        work();

        printf("Case #%d\n%d %d\n", t, ansi + 1, ansj + 1);

    }

    return 0;

}

 

下面是我的优先队列的:

/*

 * Author    : ben

 */

#include <cstdio>

#include <cstdlib>

#include <cstring>

#include <cmath>

#include <ctime>

#include <iostream>

#include <algorithm>

#include <queue>

#include <set>

#include <map>

#include <stack>

#include <string>

#include <vector>

#include <deque>

#include <list>

#include <functional>

#include <numeric>

#include <cctype>

using namespace std;

typedef long long LL;

const int MAXN = 200000;

typedef struct Mont {

    int height;

    int index;

    LL value;

    Mont(int ii = 0, int hh = 0, LL vv = 0) {

        height = hh;

        index = ii;

        value = vv;

    }

} Mont;

bool inline operator<(const Mont& m1, const Mont& m2) {

    return m1.value < m2.value;

}

LL R;

int N, m;

int data[MAXN];

LL ans;

int ansi, ansj;



inline void treat(int &i, int &j) {

    if (i >= N - m) {

        i = i % (N - m);

    }

    if (j >= N - m) {

        j = j % (N - m);

    }

    if (i > j) {

        int t = i;

        i = j;

        j = t;

    }

}



void work() {

    priority_queue<Mont> mont;

    mont.push(Mont(0, data[0], data[0]));

    for (int i = 1; i < N; i++) {

        while (mont.top().index < (i - m)) {

            mont.pop();

        }

        Mont topm = mont.top();

        LL tans = (i - topm.index) * R + data[i] + data[topm.index];

        if (tans > ans) {

            ans = tans;

            ansi = topm.index;

            ansj = i;

            treat(ansi, ansj);

        } else if(tans == ans) {

            int x = topm.index;

            int y = i;

            treat(x, y);

            if (x < ansi || (x == ansi && y < ansj)) {

                ansi = x;

                ansj = y;

            }

        }

        mont.push(Mont(i, data[i], data[i] - i * R));

    }

}



int main() {

    int T;

    scanf("%d", &T);

    for (int t = 1; t <= T; t++) {

        scanf("%d %lld", &N, &R);

        for (int i = 0; i < N; i++) {

            scanf("%d", &data[i]);

        }

        m = N / 2;

        for (int i = 0; i < m; i++) {

            data[i + N] = data[i];

        }

        N += m;

        ans = 0;

        work();

        printf("Case #%d:\n%d %d\n", t, ansi + 1, ansj + 1);

    }

    return 0;

}

 

你可能感兴趣的:(HDU)