---
# System prepended metadata

title: Free Contest Testing Round 20 - SEQ51
tags: [' Free Contest', ' Binary Search', ' Two Pointers', VNOJ, ' Sprase Table', ' SPyofgame']

---

---
tags: VNOJ, Free Contest, Sprase Table, Binary Search, Two Pointers, SPyofgame
---

Free Contest Testing Round 20 - SEQ51
===

[https://oj.vnoi.info/problem/fct020_seq51](https://oj.vnoi.info/problem/fct020_seq51)

-----

###### tags: `Sprase Table`, `Binary Search` / `Two Pointers`

-----

### Hướng dẫn

Ta muốn tìm một đoạn $[L, R]$ thỏa điều kiện $a_L \geq 1, a_{L+1} \geq 2, \dots, a_r \geq (R-L+1)$ **[1]** 

Xét dãy $b_p = a_p - p$ với $p = 1 \dots n$

Ta có **[1]** $\Leftrightarrow b_L + L \geq 1, b_{L+1} \geq 1, \dots, b_R \geq 1 \Leftrightarrow min(b_L, b_{L+1}, \dots, b_R) \geq 1$

Để cập nhật kết quả ta có thể dùng
- Chặt nhị phân
- Hai con trỏ 

Để tính min đoạn (RMQ) ta có thể dùng
- Segment Tree: $O(n)$ dựng - $O(log\ n)$ truy vấn
- Sprase Table: $O(n\ log\ n)$ dựng - $O(1)$ truy vấn
- SQRT Tree: $O(n\ log\ log\ n)$ dựng - $O(1)$ truy vấn
- Sliding Window Deque // Cartesian Tree: $O(1)$ cập nhật - $O(1)$ truy vấn

-----

### Code 0

> **Time:** $O(n^2)$
> **Space:** $O(n)$
> **Algo:** Brute-foces

```cpp=
#include <iostream>

using namespace std;

const int LIM = 1e5 + 15;

int n;
int a[LIM];
int main()
{
    ios::sync_with_stdio(NULL);
    cin.tie(NULL);

    cin >> n;
    for (int i = 1; i <= n; ++i)
        cin >> a[i];
    
    int res = 0;
    for (int i = 1; i <= n; ++i)
        for (int j = i, p = 1; j <= n && a[j] >= p; ++j, ++p)
            if (res < p)
                res = p;
    
    cout << res;
    return 0;
}
```

-----
### Code 1


> **Time:** $O(n\ log\ n)$ precal + $O(n \times log\ n)$ cal
> **Space:** $O(n\ log\ n)$
> **Algo:** Sprase Table + Binary Search

```cpp=
#include <iostream>
#include <cmath>

using namespace std;

const int LIM = 1e5 + 15;
const int LOG_LIM = ceil(log(LIM) / log(2)) + 1;

int n;
int a[LIM];
int l2[LIM];
int up[LIM][LOG_LIM];
void construct_sprase_table()
{
    l2[0] = l2[1] = 0;
    for (int i = 2; i <= n; ++i)
        l2[i] = l2[i >> 1] + 1;

    for (int i = 1; i <= n; ++i)
        up[i][0] = a[i];
    
    for (int k = 1; (1 << k) <= n; ++k)
        for (int i = 1; i + (1 << k) - 1 <= n; ++i)
            up[i][k] = min(up[i][k - 1], up[i + (1 << (k - 1))][k - 1]);

}

int query(int l, int r)
{
    int k = l2[r - l + 1];
    return min(up[l][k], up[r - (1 << k) + 1][k]);
}

int main()
{
    ios::sync_with_stdio(NULL);
    cin.tie(NULL);

    cin >> n;
    for (int i = 1; i <= n; ++i)
        cin >> a[i];
    
    for (int i = 1; i <= n; ++i)
        a[i] -= i;

    construct_sprase_table();
    int res = 0;
    for (int i = 1; i + res <= n; ++i)
    {
        int j = -1;
        for (int l = i + res, r = n; l <= r; )
        {
            int m = (l + r) >> 1;  
            if (query(i, m) + i >= 1)
            {
                j = m;
                l = m + 1;
            }
            else 
            {
                r = m - 1;
            }
        }

        if (j != -1) res = j - i + 1;
    }

    cout << res;
    return 0;
}
```

-----

### Code 2

> **Time:** $O(n\ log\ n)$ precal + $O(n)$ cal
> **Space:** $O(n\ log\ n)$
> **Algo:** Sprase Table + Two Pointers

```cpp=
#include <iostream>
#include <cmath>

using namespace std;

const int LIM = 1e5 + 15;
const int LOG_LIM = ceil(log(LIM) / log(2)) + 1;

int n;
int a[LIM];
int l2[LIM];
int st[LIM][LOG_LIM];

void construct_sparse_table()
{
    l2[0] = l2[1] = 0;
    for (int i = 2; i <= n; ++i)
        l2[i] = l2[i >> 1] + 1;

    for (int i = 1; i <= n; ++i)
        st[i][0] = a[i];
    
    for (int k = 1; (1 << k) <= n; ++k)
        for (int i = 1; i + (1 << k) - 1 <= n; ++i)
            st[i][k] = min(st[i][k - 1], st[i + (1 << (k - 1))][k - 1]);
}

int query(int l, int r)
{
    int k = l2[r - l + 1];
    return min(st[l][k], st[r - (1 << k) + 1][k]);
}

int main()
{
    ios::sync_with_stdio(NULL);
    cin.tie(NULL);

    cin >> n;
    for (int i = 1; i <= n; ++i)
    {
        cin >> a[i];
        a[i] -= i;
    }

    construct_sparse_table();
    int res = 0;
    for (int l = 1, r = 1; l <= n; ++l)
    {
        if (r < l) r = l;
        while (r + 1 <= n && query(l, r + 1) + l >= 1) ++r;
        if (res < r - l + 1)
            res = r - l + 1;
    }

    cout << res;
    return 0;
}
```


-----

### Code 3

> **Time:** $O(n)$
> **Space:** $O(n)$
> **Algo:** Sliding Window Deque

```cpp=
#include <iostream>
#include <deque>

using namespace std;

const int LIM = 1e5 + 15;

int n;
int a[LIM];
int main()
{
    ios::sync_with_stdio(NULL);
    cin.tie(NULL);

    cin >> n;
    for (int i = 1; i <= n; ++i)
    {
        cin >> a[i];
        a[i] -= i;
    }

    deque<int> S;
    int res = 0;
    for (int l = 1, r = 1; l <= n; ++l)
    {
        while (S.size() && S.front() < l) S.pop_front();
        for (r = max(l, r); r <= n; ++r)
        {
            while (S.size() && a[S.back()] >= a[r]) S.pop_back();
            S.push_back(r);
            if (a[S.front()] + l < 1) break;
            res = max(res, r - l + 1);
        }
    }

    cout << res;
    return 0;
}
```