目录
E - Max to the Right of Min:
题目大意:
思路解析:
其实这道题的题意大概就是,现在有一个数组,问这个数组的子数组中满足最小值的索引小于最大值索引的子数组个数。
那我们想是否可以通过枚举其中一个端点,来确定其他端点是否可能。
例如我们是否能构造这样的情况 [l, .... i, .... r] 在这个数组中ai的值最大,a[r] > a[l], 并且 l+1 ---- r-1这些索引的值都大于a[r],那么现在的最小值索引为l, 如果往后考虑 只要不出现一个索引 x,满足(x<l, 并且a[x] > a[i]) 那么这样的子数组都是合法的,换言之 l最多扩展到x,那我们只要预处理得到左边数字中第一个大于ai的索引值,那我们就可以快速得到以r为右端点的所有答案,
那我们可考虑这个r是否进行下一步扩展,假设a[r+1] 大于a[r],那么l‘ 可能是大于 l 的, 那我们答案是否是对于l’进行扩展呢?答案是否定的,因为a[l'] 是大于 a[r] 的,那么对于 [l' ..... i ...... r+1] 来说最小值的索引为r,此时最大值索引为i,不是合法数组了,那么扩展还是应当用l来进行扩展。 假设a[r+1] 小于 a[r], 那么l' 一定小于等于 l的那我们利用l'进行扩展,可以保证数组合法了。直到a[r'] > a[i] 时,停止计算答案。因为我们的统计建立在 a[i]为子数组的最大值的情况下,这样可以保证重复计算。
通过上述分析我们需要知道 每个位置i左边小于它的第一个数字的索引, 每个位置i左边大于它的第一个数字的索引, 每个位置i右边大于它的第一个数字的索引
那么如果 [l, i ,r] l为左边的第一个大于a[i]的索引 r 为右边的第一个大于a[i]的索引,第一种情况是遍历【i,r] 但是如果这部分区间很长,但是左部分区间很短,那么遍历右半区间明显是不利的,那我们想是否可以通过确定左端点来确定答案。
假设 [l ....... i ........ r] 其中 a[i] 为当前数组中最大的那个, a[l] > a[r], 除了r其他值都大于a[l],可以发现这个情况其实和第一种情况是类似的,最小值的索引为 r, 但是现在索引是大于i的,那我们只要选择 [i,r-1] 作为右端点,那么这个 最小值索引就为l ,为合法的。那么考虑是否可以进行扩展,如果a[l-1] > a[l] 那么 r' 可能小于r, 但是我们只要选择的右端点为[i,r-1]还是能满足数组合法,所以还是利用r作为右端点。如果a[l-1] < a[l], 那么r‘ 一定大于等于r,此时我们只要选择 [i,r'-1]时,l-1就是最小值索引,那么可以利用r’作为右端点,但是可能r' 大于了 rm (rm为右边第一个大于a[i]的索引)虽然我们选择 [rm, r‘-1] 最小值索引为l-1也能满足合法,但是此时a[i]不是作为子数组的最大值,应该排除(这部分答案,只保留 [i,rm-1]) 。那么显然a[l-1]也不能大于a[i]
通过上述分析我们需要知道 每个位置i左边小于它的第一个数字的索引, 每个位置i左边大于它的第一个数字的索引, 每个位置i右边大于它的第一个数字的索引,每个位置i右边小于它的第一个数字的索引。
代码实现:
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
int t = 1;
while (t > 0) {
solve();
t--;
}
w.flush();
w.close();
}
static int mod = 998244353;
static long inf = (long) 1e18;
static long ans = 0;
public static void solve() throws IOException {
int n = f.nextInt();
int[] a = new int[n+1];
int[] lmi = new int[n+1];
int[] rmi = new int[n+1];
int[] lma = new int[n+1];
int[] rma = new int[n+1];
for (int i = 1; i <= n; i++) {
a[i] = f.nextInt();
}
int tp = 0;int[] st = new int[1000005];
tp = 0; st[0] = 0;
for(int i = 1; i <= n; ++i){
while(tp > 0 && a[i] < a[st[tp]]) --tp;
lmi[i] = st[tp];
st[++tp] = i;
}
tp = 0; st[0] = 0;
for(int i = 1; i <= n; ++i){
while(tp > 0&& a[i] > a[st[tp]]) --tp;
lma[i] = st[tp];
st[++tp] = i;
}
tp = 0; st[0] = n + 1;
for(int i = n; i >= 1; --i){
while(tp > 0 && a[i] < a[st[tp]]) --tp;
rmi[i] = st[tp];
st[++tp] = i;
}
tp = 0; st[0] = n + 1;
for(int i = n; i >= 1; --i){
while(tp > 0 && a[i] > a[st[tp]]) --tp;
rma[i] = st[tp];
st[++tp] = i;
}
for (int i = 1; i <= n; i++) {
int lm = lma[i]; int rm = rma[i];
if (i - lm >= rm - i){
int cur = n;
for (int j = i; j < rm; j++) {
cur = Math.min(cur, lmi[j]);
ans += Math.max(0, cur - lm);
}
}else {
int cur = i;
for (int j = i; j > lm; --j) {
if(a[j] < a[cur]) cur = j;
if(cur != i){
ans += Math.max(0, Math.min(rmi[cur], rm) - i);
}
}
}
}
w.println(ans);
}
static int gcd(int a, int b) {
if (a == 0) return b;
if (b == 0) return a;
return gcd(b, a % b);
}
public static int qkm(int a, int b) {
int res = 1;
while (b > 0) {
if ((b & 1) == 1) res *= a;
a *= a;
b >>= 1;
}
return res;
}
public static void swap(int[] a, int i, int j) {
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
public static long qkm(long a, long b, long mod) {
long res = 1;
while (b > 0) {
if ((b & 1) == 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
public static class Node {
int a;
int b;
public Node(int x, int val) {
this.a = x;
this.b = val;
}
public Node(){}
}
static PrintWriter w = new PrintWriter(new OutputStreamWriter(System.out));
static Input f = new Input(System.in);
static class Input {
public BufferedReader reader;
public StringTokenizer tokenizer;
public Input(InputStream stream) {
reader = new BufferedReader(new InputStreamReader(stream), 32768);
tokenizer = null;
}
public String next() throws IOException {
while (tokenizer == null || !tokenizer.hasMoreTokens()) {
tokenizer = new StringTokenizer(reader.readLine());
}
return tokenizer.nextToken();
}
public String nextLine() throws IOException {
String str = null;
str = reader.readLine();
return str;
}
public int nextInt() throws IOException {
return Integer.parseInt(next());
}
public long nextLong() throws IOException {
return Long.parseLong(next());
}
public Double nextDouble() throws IOException {
return Double.parseDouble(next());
}
}
}