Fady and Stable Arrays#12482

Fady and Stable Arrays (Розбір)

Автор задачі:

Fady Rafat (FADY)

Підготував:

Fady Rafat (FADY)

Відредагував:

Hasan Saleh (MathModel)

Розв'язок

Загальна ідея: Потрібно порахувати кількість різних стабільних масивів (у яких жодні два сусідніх елементи не рівні), які можна отримати, застосовуючи операції до початкового масиву.

Ключове спостереження:

Коли ми застосовуємо операцію до двох сусідніх рівних елементів a_i = a_{i+1} = v, ми замінюємо їх одним елементом зі значенням v + 1. Це означає, що ми можемо «злити» суміжні блоки однакових значень у більші значення.

Більш формально, неперервний підмасив однакових значень [v, v, \ldots, v] довжини 2^k можна злити в один елемент зі значенням v + k.

Формулювання ДП:

Нехай = найлівіший початковий індекс такий, що підмасив a[L[i][v] \ldots i] можна злити у значення .

Це можна обчислити так:

  • L[i][a[i]] = i (один елемент зливається сам у себе)

  • L[i][v] = L[L[i][v-1] - 1][v-1], якщо підмасив, що закінчується в і зливається у v-1, може бути передований іншим підмасивом, який також зливається у v-1

Нехай dp[i][v] = кількість стабільних масивів, що закінчуються в позиції з останнім елементом зі значенням .

Нехай = загальна кількість стабільних масивів, що закінчуються в позиції .

Перехід:

  • Якщо L[i][v] = 0: dp[i][v] += 1 (весь префікс зливається у )

  • Інакше: dp[i][v] += ans[L[i][v] - 1] - dp[L[i][v] - 1][v]

Ми віднімаємо dp[L[i][v] - 1][v], щоб уникнути двох суміжних блоків з однаковим значенням (умова стабільності).

Нарешті:

ans[i] = \sum_{v} dp[i][v]

Відповідь — ans[n-1].

Аналіз складності:

Обчислення : \mathcal{O}(n \cdot V), де V = 80 + \log_2(n) \approx 102.

Обчислення : \mathcal{O}(n \cdot V).

Загальна складність на один тест: \mathcal{O}(n \cdot V).

#include <bits/stdc++.h>
using namespace std;

const int MOD = 1e9 + 7;
const int MAX_V = 102;

void solve() {
    int n;
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; i++)
        cin >> a[i];
    
    vector<vector<int>> L(n, vector<int>(MAX_V, -1));
    vector<vector<long long>> dp(n, vector<long long>(MAX_V, 0));
    vector<long long> ans(n, 0);
    
    for (int i = 0; i < n; i++) {
        L[i][a[i]] = i;
        for (int v = a[i] + 1; v < MAX_V; v++) {
            int right_start = L[i][v - 1];
            if (right_start > 0) {
                int left_start = L[right_start - 1][v - 1];
                if (left_start != -1)
                    L[i][v] = left_start;
            }
        }
        for (int v = 0; v < MAX_V; v++) {
            int start = L[i][v];
            if (start == -1) continue;
            if (start == 0) {
                dp[i][v] = (dp[i][v] + 1) % MOD;
            } else {
                long long ways = (ans[start - 1] - dp[start - 1][v] + MOD) % MOD;
                dp[i][v] = (dp[i][v] + ways) % MOD;
            }
            ans[i] = (ans[i] + dp[i][v]) % MOD;
        }
    }
    
    cout << ans[n - 1] << "\n";
}

int main() {
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}