#include <bits/stdc++.h>
using namespace std;
const int MAX = 500005;
const int MOD = 1000000007;
int N;
int A[MAX];
int s[MAX];
int index_left[MAX];
int L_max[MAX];
int R_max[MAX];
int dp[MAX];
int prefix_sum[MAX];
int sum(int l, int r) {
if (l == 0) return prefix_sum[r];
return (prefix_sum[r] - prefix_sum[l - 1]) % MOD;
}
int solve() {
// index_left[i] = Largest index j <= i and such that A[j..i] obeys the first
// condition i.e. min(A[j..i]) <= (i - j + 1).
// If index_left[i] <= 0, then no such 'j' exists.
// We use dequeue where we maintain a strictly growing value of A[i].
int l = 1, r = 0;
for (int i = 1; i <= N; i++) {
while (l <= r && A[i] <= A[s[r]]) {
r--;
}
s[++r] = i;
// We try to find the largest value of 'j'. So, we try to left shift till
// it is possible to do so.
while (l < r && min(s[l], i - A[s[l]] + 1) <= min(s[l + 1], i - A[s[l + 1]] + 1)) {
l++;
}
index_left[i] = min(s[l], i - A[s[l]] + 1);
}
// L_max[i] = Largest index j < i such that A[j] > A[i]. If no such index "j"
// exists, we let L_max[i] = 0.
// It can be solved using stack using a modification of "stock span problem".
// You can look at https://w...content-available-to-author-only...s.org/the-stock-span-problem/
// for more details. The author uses idea similar to failure function in
// kmp algorithm. The complexity is O(N). Here failing for index "i" means
// going to largest index "j" such that A[j] > A[i].
for (int i = 1; i <= N; i++) {
int curr = i - 1;
while (curr != 0 && A[curr] <= A[i]) {
curr = L_max[curr];
}
L_max[i] = curr;
}
// R_max[i] = Smallest index j > i such that A[j] >= A[i]. If no such index "j"
// exixts, we let R_max[i] = N + 1;
// Calculation is similar to L_max[i]. Complexity is O(N).
for (int i = N; i >= 1; i--) {
int curr = i + 1;
while (curr <= N && A[curr] < A[i]) {
curr = R_max[curr];
}
R_max[i] = curr;
}
// Complexity of the code till now is O(N) for all the 3 loops. :)
// dp[i] denotes number of valid partitions in the array A[1..i].
// prefix_sum[i] = sum_{x=1}^{x=i} dp[x]
for (int i = 1; i <= N; i++) {
dp[i] = 0;
}
// Number of partition for null sequence is 1.
dp[0] = 1;
prefix_sum[0] = 1;
int currSum = 0;
for (int i = 1; i <= N; i++) {
// We assume all the values of dp[i-1] and prefix sum of dp is calculated
// correctly before this loop. This is the inductive hypothesis and we try
// to calculate the correct value of dp[i] in this iteration and thus add it
// to prefix sum as well to make sure it is correctly calculated.
// currSum takes care of the following 2 cases:
// 1. Sum of all paritions where index 'j' is part of partition obeying the
// second condition and A[j] was the maximum in the partition.
// 2. The faulty paritions containing 'i' which obeyed first condition but
// did not obtain the second condition. This is already stored in dp[i]
// by subtracting contribution from 1 to (i-1) wherever applicable. Note
// that dp[i] was initialised with 0 and can only be negative at this
// moment to due subtraction by faulty values.
currSum = (currSum + dp[i]) % MOD;
// Condition 2 of safe parition is:
// Length of partition <= Maximum in the partition.
// We need to find subarrays where condition 2 is obeyed and A[i] is the
// maximum in the subarray.
// By definition of L_max[i] and R_max[i], A[i] in maximum in [l..r] where
// L_max[i] <= l <= i and i <= r <= R_max[i]
// Note that for calculating dp[i], we need a valid partition from
// [(j+1)..i] where j < i and add the contribution of dp[j] to dp[i].
// So, we need to consider subarrays ending at 'i' only which simplifies the
// problem a bit. So for [(j+1)..i], the condition is
// (i - j) <= A[i]
// j >= (i - A[i])
// We also want A[i] to be maximum, so the valid positions should start
// after L_max[i] by definition.
// This explains the below values for variable 'l' and 'r'.
int l = max(i - A[i], L_max[i]);
int r = i - 1;
// add dp[l..r] to currSum where we add the contribution of part 1 as per
// definition of currSum on line 83.
currSum = (currSum + sum(l, r)) % MOD;
// Find the exact value of dp[i].
if (index_left[i] <= 0) {
// If A[1..i] doesn't obey condition 1, then even if we partition it into
// smaller parts where initial part obey both condition 1 and 2, the last
// partition containing 'i' will still not obey condition 1. This is due
// to the defintion of index_left for finding the maximum possible 'j' for
// every index.
dp[i] = 0;
}
else {
// If A[1..i] obeys the condition 1, then any subarray from [j..i] where
// index_left[i] <= j <= i-1 is not safe as first condition is not obeyed
// as per defintion of index_left[i].
// Consider this scenario as trying to add dp[j] to dp[i] in brute force
// algorithm but it is not possible as [j..i] is not safe.
// Note that part 1 for defintion in currSum on line 83 can violate
// condition 1 and this basically takes care of such situations.
dp[i] = (currSum - sum(index_left[i], i - 1)) % MOD;
}
// Handle the case of negative modulus.
if (dp[i] < 0) {
dp[i] = (dp[i] + MOD) % MOD;
}
// Update the prefix_sum array.
prefix_sum[i] = (prefix_sum[i - 1] + dp[i]) % MOD;
// Now we want to want faulty subarrays where A[i] was the maximum, the
// first condition was obeyed by the second condition was violated and
// subtract the value of faulty partitions from the respective dp[] i.e. we
// are solving for condition 2 for currSum on line 85.
// Now for such subarrays we know their left end point should start before
// index 'i' and their right end points has to end before R_max[i].
// curr is set as 'l' as it the starting point where A[i] can be maximum as
// explained before.
// The subarray being considered is [curr..x]. To disobey second condition
// the length should be greater than maximum i.e. A[i]
// length > A[i].
// So, for given curr, the first such right end point is (curr + A[i] + 1)
// This should be less than or equal to R_max[i].
// If this is less than R_max[i], then curr is the only such left end point
// for a fixed end point as moving forward, the length of partition
// decreases but maximum still remains A[i], which doesn't lead to violation
// of condition 2.
int curr = l;
while (curr < i && curr + A[i] + 1 < R_max[i]) {
dp[curr + A[i] + 1] = (dp[curr + A[i] + 1] - dp[curr]) % MOD;
curr++;
}
if (curr + A[i] + 1 >= R_max[i]) {
// If need to check for greater or equal than and subtract a range sum
// here as all subarrays will have right end point as R_max[i] and left
// end point from [curr..r] but can't have A[i] as the maximum.
// Consider this scenario as trying to add dp[curr] to dp[R_max[i]] in
// brute force algorithm but it is not possible as subarray
// [(cur+1)..R_max[i]] is not safe as second condtion is violated.
dp[R_max[i]] = (dp[R_max[i]] - sum(curr, r)) % MOD;
}
}
/*
Complexity Analysis of above loop:
Note that all operations are O(1) except the while loop from line 158 to 161.
For the analysis of this while loop over all possible indices 'i', let we
consider the 2 sceanrios for variable 'l' on line 107.
Case 1: l = i - A[i]
The total movement in while loop in this case is
O(min(A[i], R_max[i] - i))
Case 2: l = L_max[i]
The total movement in while loop in this case is
O(min(i - L_max[i], R_max[i] - L_max[i] - A[i]))
Neglect the +1/-1 in above calculations, we are representing Big-O complexity.
Let's try to do a naive calculation where in case 1, we always end up using
(R_max[i] - i) and in second case we always end up using (i - L_max[i]). In
case, this was not the case, the number of movement just decreases, so be are
better off in that case.
Now, we try to chose the largest possible position of 'l' to start from in
line 107. So, for every index 'i' we will end up using minimum of above 2
movements, i.e. min(i - L_max[i], R_max[i] - i)
This means for every index we end up chosing the smallest subarray, either to
left or right side where A[i] is maximum.
Theoretically, we can have the span for every index 'i' as the whole subarray
where it is maximum. i.e. R_max[i] - L_max[i] ~ O(N).
So, the overall complexity analysis is sum_{i=1}^{i=N} O(min(a, b)) where
O(a) + O(b) = O(N).
Using the detailed analysis from https://c...content-available-to-author-only...s.com/blog/entry/56345,
our complexity for this part of O(N logN), which is a very loose upper bound.
*/
return dp[N];
}
int main() {
// Input.
scanf("%d", &N);
for (int i = 1; i <= N; ++i) {
scanf("%d", &A[i]);
}
printf("%d\n", solve());
return 0;
}
/*
Some testcases:
7
1 6 2 3 4 3 4
15
1 1 2 3 5 5 6 7 7 10 10 11 12
15
2 1 2 3 4 2 1 3 2 4 3 1 4 2 5
*/