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; }