CF982D Shark

思路:

给定k之后,求解的过程其实类似于一个“分段”的过程,即把所有大于等于k的数去掉,判断剩下的若干段是否满足条件。这样扫描一次是O(n)的,如果对所有的k都这样做一次,那么复杂度很高(O(n2))。所以需要优化,使得对于每个k不必O(n)。具体来说,我们使用set动态模拟“分段”的过程,set中存放的若干个“段”的起点和终点(初始时只有一个段(1,n))。首先将a数组按照从大到小排序,然后从前到后遍历数组,从set中找到当前数字所在的段,并根据数字所在位置将此段一分为二,判断此时是否满足条件并更新最优答案,直至结束。判断是否满足条件的方法是用map动态维护不同长度的段的个数,若这些段的长度种类只有一种就是可以的。算法的时间复杂度大约是O(n * log(n))。

实现:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int MAXN = 100005;
 5 const int INF = 0x3f3f3f3f;
 6 
 7 typedef pair<int, int> pii;
 8 
 9 pii a[MAXN];
10 
11 int main()
12 {
13     int n;
14     while (cin >> n)
15     {
16         for (int i = 1; i <= n; i++) { cin >> a[i].first; a[i].second = i; }
17         sort(a + 1, a + n + 1);
18         set<pii> st; st.insert(pii(1, n));
19         map<int, int> mp; mp[n] = 1;
20         int maxn = 0, ans = -1;
21         for (int i = n; i >= 1; i--)
22         {
23             if ((int)mp.size() == 1 && mp.begin()->second >= maxn)
24             {
25                 maxn = mp.begin()->second; ans = a[i].first + 1;
26             }
27             auto it = st.upper_bound(pii(a[i].second, INF));
28             it--;
29             if (it->first <= a[i].second - 1)
30             {
31                 pii x(it->first, a[i].second - 1);
32                 st.insert(x);
33                 mp[x.second - x.first + 1]++;
34             }
35             if (a[i].second + 1 <= it->second)
36             {
37                 pii y(a[i].second + 1, it->second);
38                 st.insert(y);
39                 mp[y.second - y.first + 1]++;
40             }
41             int l = it->second - it->first + 1;
42             st.erase(it);
43             mp[l]--; if (!mp[l]) mp.erase(l);
44         }
45         cout << ans << endl;
46     }
47     return 0;
48 }
原文地址:https://www.cnblogs.com/wangyiming/p/9072913.html