《算法竞赛·快冲300题》将于2024年出版,是《算法竞赛》的辅助练习册。
所有题目放在自建的OJ New Online Judge。
用C/C++、Java、Python三种语言给出代码,以中低档题为主,适合入门、进阶。
文章目录
- 题目描述
- 题解
- C++代码
- Java代码
- Python代码
“ 凹” ,链接: http://oj.ecustacm.cn/problem.php?id=1845
题目描述
【题目描述】 给定一个长度为n的数组a,请求出存在多少个二元组<i,j>满足“凹”的性质:
1、1≤i<j≤n;
2、对于所有的i<k<j均满足a[i]>a[k],a[j]>a[k]。
注意,当j=i+1时,k不存在,也满足上述约束。
给 。
【输入格式】 第一行为正整数n,n≤1000000。
接下来n行,每行一个a[i],1≤a[i]≤n,a[i]不互相同。。
。
【输出格式】 输出一个数字表示答案。。
【输入样例】
样例1:
3
2
1
3
样例2:
6
1
3
2
6
4
5
【输出样例】
样例1:
3
样例2:
7
题解
首先模拟检查“凹”,了解执行的过程。以“3 1 2 6”为例,其中的“凹”有:“3 1 2”和“3 1 2 6”;还有j = i + 1的“3 1”、“1 2”、“2 6”。一共5个。
像“3 1 2”和“3 1 2 6”这样的“凹”,需要检查连续的3个以上的数字。
例如“3 1 2”,从“3”开始,下一个应该比“3”小,例如“1”,再后面的数字比“1”大,才能形成“凹”。
再例如“3 1 2 6”,前面的“3 1 2”已经是“凹”了,最后的“6”也会形成新的“凹”,条件是这个“6”必须比中间的“1 2”大才行。
总结上述过程是:先检查“3”;再检查“1”符合“凹”;再检查“2”,比前面的“1”大,符合“凹”;再检查“6”,比前面的“2”大,符合“凹”。
以上是检查一个“凹”的两头,还有一种是“嵌套”。一旦遇到比前面小的数字,那么以这个数字为头,可能形成新的“凹”。例如“6 4 2 8”,其中的“6 4 2 8”是“凹”,二内部的“4 2 8”也是凹。如果学过递归、栈,就会发现这是嵌套,所以本题用栈来做很合适。
以“3 1 2 6”为例,用栈模拟找“凹”。当新的数比栈内的数小,就进栈;如果比栈内的数大,就出栈,并记录找到了一个“凹”。
然而,上述讨论隐含了一个前提,就是“凹”的尾部比头大,所以只能找到“头<尾”的“凹”。如何找“头>尾”的“凹”?只需反过来用栈执行一遍就行了。
【笔记】 栈的应用 。
C++代码
#include<bits/stdc++.h>
using namespace std;
int a[1000010];
stack<int>s;
int ans;
int main(){
int n; scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
//从头到尾
for(int i = 1; i <= n; i++){
while(!s.empty() && s.top() < a[i])
ans++, s.pop();
s.push(a[i]);
}
while(!s.empty()) //清空栈s
s.pop();
//从尾到头
for(int i = n; i >= 1; i--){
while(!s.empty() && s.top() < a[i])
ans++, s.pop();
s.push(a[i]);
}
cout<<ans<<endl;
return 0;
}
Java代码
import java.util.Scanner;
import java.util.Stack;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] a = new int[n];
for (int i = 0; i < n; i++)
a[i] = sc.nextInt();
sc.close();
Stack<Integer> s = new Stack<Integer>();
int ans = 0;
// 从头到尾
for (int i = 0; i < n; i++) {
while (!s.empty() && s.peek() < a[i]) {
ans++;
s.pop();
}
s.push(a[i]);
}
s.clear();
// 从尾到头
for (int i = n - 1; i >= 0; i--) {
while (!s.empty() && s.peek() < a[i]) {
ans++;
s.pop();
}
s.push(a[i]);
}
System.out.println(ans);
}
}
Python代码
注意两点:用setrecursionlimit扩栈,用readline加快读入速度。
import sys
sys.setrecursionlimit(1000000)
input = sys.stdin.readline #加这句后读入会快些
a = []
s = []
ans = 0
n = int(input())
for _ in range(n): a.append(int(input()))
# 从头到尾
for i in range(n):
while len(s) > 0 and s[-1] < a[i]:
ans += 1
s.pop()
s.append(a[i])
s.clear()
# 从尾到头
for i in range(n-1, -1, -1):
while len(s) > 0 and s[-1] < a[i]:
ans += 1
s.pop()
s.append(a[i])
print(ans)