hdu5261單調隊列

題意特難懂,我看了好多遍,最後仍是看討論版裏別人的問答,才搞明白題意,真是汗。ios

其實題目等價於給n個點,這n個點均勻分佈在一個圓上(知道圓半徑),點與點之間的路程(弧長)已知,點是有權值的,已知,點與點的距離等於其最短路程(弧長)加上兩點的權值,問距離最遠的兩個點的下標。spa

由於是環狀,很差處理,因此我在輸入的時候就簡單處理了一下,使問題變成直線上的等價問題了。作法就是在輸入序列後面再加上前半段序列,例如樣例5 2 1 10 1 10 10,能夠處理成1 10 1 10 10 1 10,這樣就只須要順序處理了,不過最後輸成的下標是須要處理的,由於要求的是字典序最小的下標對。code

變成直線後的問題就比較簡單了。便於理解的作法是維護一個長度爲半圓的隊列,當處理i時,把隊列裏的點和i點比較,更新最值,而後i入隊,隊列頭元素出隊。這是n^2的效率,換成單調隊列,就能過了。不過,我是用優先隊列作的,代碼比用單調隊列稍複雜一丁點,也是腦子木了,還沒打完,金牛就把我代碼要了去用單調隊列接着打了。先貼上金牛的單調隊列的代碼,再貼個人,都是1a:blog

/*
 * 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;
}
相關文章
相關標籤/搜索