Fady and Stable Arrays#12482

Fady and Stable Arrays (Editorial)

Problem Author:

Fady Rafat (FADY)

Prepared by:

Fady Rafat (FADY)

Edited by:

Hasan Saleh (MathModel)

Solution

General Idea: We need to count distinct stable arrays (no two adjacent elements equal) that can be formed by applying operations on the original array.

Key Observation:

When we apply the operation on two adjacent equal elements a_i = a_{i+1} = v, we replace them with a single element of value v + 1. This means we can "merge" adjacent blocks of equal values into higher values.

More formally, a contiguous subarray of identical values [v, v, \ldots, v] of length 2^k can be merged into a single element of value v + k.

DP Formulation:

Let = the leftmost starting index such that the subarray a[L[i][v] \ldots i] can be merged into value .

This can be computed as:

  • L[i][a[i]] = i (a single element merges to itself)

  • L[i][v] = L[L[i][v-1] - 1][v-1] if the subarray ending at that merges to v-1 can be preceded by another subarray that also merges to v-1

Let dp[i][v] = number of stable arrays ending at position with last element value .

Let = total number of stable arrays ending at position .

The transition is:

  • If L[i][v] = 0: dp[i][v] += 1 (the entire prefix merges to )

  • Otherwise: dp[i][v] += ans[L[i][v] - 1] - dp[L[i][v] - 1][v]

We subtract dp[L[i][v] - 1][v] to avoid two adjacent blocks with the same value (stability condition).

Finally:

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

The answer is ans[n-1].

Complexity Analysis:

computation: \mathcal{O}(n \cdot V) where V = 80 + \log_2(n) \approx 102.

computation: \mathcal{O}(n \cdot V).

Total per test case: \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;
}