題意特難懂,我看了好多遍,最後仍是看討論版裏別人的問答,才搞明白題意,真是汗。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; }