POJ-3250 Bad Hair Day
题目大意
有 N N N 头牛从左到右排成一排,每一头牛都有一个高度 h i h_i hi ,设左数第 i i i 头牛与它右边第一头高度 ≥ h i \ge h_i ≥hi 的牛之间有 c i c_i ci 头牛,求 ∑ i = 1 N c i \sum_{i=1}^Nc_i ∑i=1Nci .
思路1:暴力
- 对于每一头牛 i i i,找到其右边的比它高的牛 j j j,然后将 j − i j-i j−i求和即可。
- 复杂度分析:
- 时间复杂度:
O
(
n
2
)
O(n^2)
O(n2). 显然,i和j都需要两层循环。
- n的最大值是8e4,显然,会TLE。
- 空间复杂度: O ( n ) O(n) O(n),需要一个数组存储。
- 时间复杂度:
O
(
n
2
)
O(n^2)
O(n2). 显然,i和j都需要两层循环。
思路2:单调栈
-
维护一个栈,这个栈是 严格单调递减 的。当遍历到第 i i i 头牛时,如果这头牛的高度 h i h_i hi 大于等于栈顶元素,那么将栈顶元素弹栈,直到 h i < h_i< hi< 栈顶元素,然后将 h i h_i hi 压栈。以此来维护栈的单调性。
-
如果我们维护了这样一个栈,很容易发现,当压入一个新元素 h i h_i hi 时,栈中元素的个数-1,就是加入这头牛后,它左边的牛能够看到它的个数,因此,将结果加上这个数即可。
根据上述思路很容易写出AC代码:
#include<iostream>
#include<stack>
#include<vector>
using namespace std;
long long poj_3250(){
int N;
scanf("%d", &N);
stack<int> stk;
long long ret = 0;
while (N --){
int tmp;
scanf("%d", &tmp);
while (!stk.empty() && stk.top() <= tmp){
stk.pop();
}
stk.push(tmp);
ret += (stk.size() - 1);
}
return ret;
}
int main(){
cout << poj_3250() << endl;
return 0;
}
Times:454ms Mem:1MB
-
注意:
ret
的返回值应该是long long
!(铁头娃因此WA了好几发。) -
注意2:VJ的判题系统的编译器是C98,因此不支持C++11的新特性,因此无法使用auto。
-
复杂度分析:
- 时间复杂度: O ( n ) O(n) O(n). 只需要进行一次遍历即可。
- 空间复杂度: O ( 1 ) O(1) O(1). 因为使用了输入流,因此空间优化至常数。
思路3:
写了半天思路三,结果到最后发现是错误的😰
思路平平无奇,这里不传播错误想法了。只贴个代码,能看懂的,一定是同道中人😋
#include<iostream>
#include<vector>
#include<set>
using namespace std;
struct cmp{
bool operator()(const pair<int, int> &l, const pair<int, int> &r){
return l.first < r.first || (l.first == r.first && l.second < r.second);
}
};
long long poj_3250(){
const int INF = 0x3f3f3f3f;
long long ret = 0;
int N;
scanf("%d", &N);
vector<int> h;
set<pair<int, int>, cmp> recorder;
while (N --){
int tmp;
scanf("%d", &tmp);
h.push_back(tmp);
}
h.push_back(INF);
for (int i = 0; i < h.size(); i ++){
recorder.insert(pair<int, int>(h[i], i));
}
for (auto i : recorder){
cout << i.first << " " << i.second << endl;
}cout << endl;
for (int i = 0; i < h.size() - 1; i ++){
set<pair<int, int>> :: iterator it = recorder.upper_bound(pair<int, int>(h[i], i));
ret += (it->second - i - 1);
cout << i << " " << h[i] << "," << it->second << " " << it->first << " " << (it->second - i - 1) << endl;
recorder.erase(pair<int, int>(h[i], i));
}
return ret;
}
int main(){
cout << poj_3250() << endl;
return 0;
}
- 如果正确的话,时间复杂度是: O ( n l o g n ) O(nlogn) O(nlogn);空间复杂度是: O ( n ) O(n) O(n).
- 只可惜不正确QWQ
2021.3.25 23:19