---
# System prepended metadata

title: Olympic Sinh Viên 2020 - Chuyên tin - VCA
tags: [' Olympic', ' Olympic Sinh Vien', ' Two Pointers', VNOJ, ' SPyofgame']

---

---
tags: VNOJ, Olympic, Olympic Sinh Vien, Two Pointers, SPyofgame
---

Olympic Sinh Viên 2020 - Chuyên tin - VCA
===

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

-----

###### tags: `Two Pointers`

-----

### Hướng dẫn

Với mỗi vị trí $[L]$ tìm vị trí $[R]$ nhỏ nhất thỏa mãn số lượng kí tự '**A**', '**V**' và '**C**' trong đoạn $[L, R]$ đều không ít hơn $k$

Vì lúc này $[L, R]$ là một đoạn cố định tương tự như mình xóa $[1, L)$ và $(R, N]$ mà không mất chi phí, nên giờ mình sẽ xóa phần bên trong, sao cho số lượng '**A**', '**V**' và '**C**' đều có đúng $k$.

Gọi $C_{_X}$ là số lượng kí tự có giá trị $X$ trên đoạn $[L, R]$. Chi phí sửa đổi của đoạn $[L, R]$ là $C_{_A} + C_{_V} + C_{_C} - 3k)$. 

Vậy bài này có độ phức tạp là $O(n)$ thời gian và bộ nhớ

- Mình có thể tìm $R$ bằng hai con trỏ thay cho chặt nhị phân
- Mình có thể sử dụng mảng cộng dồn hoặc một số cấu trúc dữ liệu để $O(n)$ tiền xử lí và $O(1)$ truy vấn.

-----

### Code

> **Time:** $O(n)$
> **Space:** $O(n)$ 
> **Algo:** Two Pointers

```cpp=
#inlude <iostream>

using namespace std;

int cnt[256];
int main()
{
    /// Input
    int k;
    string s;
    cin >> k >> s;
    
    /// Calculate
    int res = +INF;
    cnt['A'] = cnt['V'] = cnt['C'] = 0;
    for (int l = 0, r = -1; l < s.size(); --cnt[s[l++]])
    {
        while (r + 1 < s.size() && (cnt['A'] < k || cnt['V'] < k || cnt['C'] < k)) ++cnt[s[++r]];
        if (cnt['A'] < k || cnt['V'] < k || cnt['C'] < k) break;

        int t = 0;
        t += cnt['A'] - k;
        t += cnt['V'] - k;
        t += cnt['C'] - k;
        minimize(res, t);
    }
    
    /// Output
    cout << res;
    return 0;
}
```