Автор задачі: | 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[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;
}