单调栈&二分写法
cf 上 tourist 题解的单调栈和二分的写法
#include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(0); int n; cin >> n; vector<int> a(3 * n); for (int i = 0; i < n; i++) { cin >> a[i]; a[i + n] = a[i + 2 * n] = a[i]; } vector<int> ans(3 * n); vector<int> st_max; vector<int> st_min; //因为看成最大圈来做,所以是3n for (int i = 3 * n - 1; i >= 0; i--) { //倒着来,才能完美运用单调栈 while (!st_max.empty() && a[st_max.back()] < a[i]) { st_max.pop_back(); //单调减栈 (下标) } while (!st_min.empty() && a[st_min.back()] > a[i]) { st_min.pop_back(); //单调增栈 (下标) } int low = 0, high = (int) st_min.size(); while (low < high) { //在减栈中二分找到第一个满足条件的下标 int mid = (low + high) >> 1; if (a[st_min[mid]] * 2 < a[i]) { low = mid + 1; } else { high = mid; } } int nxt = 3 * n; if (low > 0) { nxt = min(nxt, st_min[low - 1]); } if (!st_max.empty()) { nxt = min(nxt, st_max.back()); //增栈中找到第一个大于的下标 } if (nxt < 3 * n && a[nxt] >= a[i]) { ans[i] = ans[nxt]; //如果先出现大于的,那么ans就和nxt指向的那个点一样 } else { ans[i] = nxt; //如果先出现符合退出条件的,那么nxt值就是答案 } st_min.push_back(i); st_max.push_back(i); } for (int i = 0; i < n; i++) { if (i > 0) { cout << " "; } cout << (ans[i] == 3 * n ? -1 : ans[i] - i); } cout << '\n'; return 0; }

浙公网安备 33010602011771号