比武
题目
by 郑瑜
描述
有 \(N\) 个比武者排成一排. 事先已经得知他们的战力; 对于两个比武者, 若他们之间 (不包括他们自己) 没有人战力大于他们当中的较小战力, 则他们需要一次比武. 求比武次数.
提示: 对于任意比武者, 排在其前面且战力较小的人不会和排在其后面的人比武. \(1 \leq\) 战力 \(< 231\). 人数: 1-2: \(N \leq 1 \times 10^3\); 3-4测试样例: \(1 \times 10^3 < N \leq 1 \times 10^4\); 5-10测试样例: \(1 \times 10^4 < N \leq 5 \times 10^5\).
IO格式
输入:
N
第1个比武者战力
...
输出:
比武次数
样例
输入1:
8
2
7
1
6
5
3
4
2
输出1:
9
输入2:
5
4
2
2
2
5
输出2:
10
解答
思路
这道题是在约三个月前做的, 所以已经不太记得细节了.
具体而言, 我们以一种特殊栈 (单调栈) 来处理: 这种特殊栈以一个常数区间为单元存储, 并且维护 secLen
(倒数第二个单元的区间长度).
计算方法是, 同一区间内总可以比武; 如果前一区间大于现区间, 可以将前一区间的最后一个人加入比武; 如果前一区间小于现区间, 那么, 我们将连续弹出前区间直至我们的栈重新单调. 计数的总原则是 cur
前面的不大于 cur
及大于 cur
的最后一个应当计入.
参考:
代码
#include <cstdio>
#include <stack>
using namespace std;
#define prf printf
#define scf scanf
#define ull size_t
template <typename T>
struct StkUnit {
StkUnit(T _val) : val(_val), len(1){};
T val;
int len;
};
template <typename T>
struct Stk {
Stk() : slen(0), secLen(0){};
stack<StkUnit<T>> s;
int slen;
int secLen;
void push(T);
void pop();
void popUnit();
T& top();
StkUnit<T>& topUnit();
};
template <typename T>
void Stk<T>::push(T _val) {
if (slen == 0) {
s.push(StkUnit<T>(_val));
slen++;
} else {
if (_val == s.top().val)
s.top().len++;
else {
secLen = s.top().len;
s.push(StkUnit<T>(_val));
slen++;
}
}
}
template <typename T>
void Stk<T>::pop() {
if (slen == 0) return;
auto& top = s.top();
top.len--;
if (top.len == 0) {
s.pop();
slen--;
if (slen == 0 || slen == 1)
secLen = 0;
else {
auto temp = s.top();
s.pop();
secLen = s.top().len;
s.push(temp);
}
}
}
template <typename T>
void Stk<T>::popUnit() {
if (slen == 0) return;
s.pop();
slen--;
if (slen == 0 || slen == 1)
secLen = 0;
else {
auto temp = s.top();
s.pop();
secLen = s.top().len;
s.push(temp);
}
}
template <typename T>
T& Stk<T>::top() {
return s.top().val;
}
template <typename T>
StkUnit<T>& Stk<T>::topUnit() {
return s.top();
}
int main() {
int N;
Stk<int> stk;
scf("%d", &N);
int cur;
ull ret = N - 1;
for (auto i = 0; i < N; i++) {
scf("%d", &cur);
if (stk.slen == 0) {
stk.push(cur);
continue;
}
auto& top = stk.top();
if (cur < top) {
stk.push(cur);
} else if (cur == top) {
ret += stk.topUnit().len - 1 + bool(stk.secLen);
stk.push(cur);
} else {
stk.pop();
while (stk.slen && stk.top() < cur) {
ret += stk.topUnit().len;
stk.popUnit();
}
if (stk.slen) {
if (stk.top() > cur)
ret += bool(stk.topUnit().len);
else if (stk.top() == cur)
ret += stk.topUnit().len + bool(stk.secLen);
}
stk.push(cur);
}
}
prf("%llu", ret);
return 0;
}
时空消耗
1 Accepted 0 ms 916 KB
2 Accepted 0 ms 920 KB
3 Accepted 0 ms 920 KB
4 Accepted 0 ms 916 KB
5 Accepted 36 ms 912 KB
6 Accepted 60 ms 912 KB
7 Accepted 68 ms 916 KB
8 Accepted 68 ms 2788 KB
9 Accepted 68 ms 2084 KB
10 Accepted 52 ms 916 KB