Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
Because , the sequence is automatically nondecreasing. So each must fit not only under , but under every later too.
Replace by . This does not change the answer, and now is nondecreasing. For every value , define as the first position where is allowed.
Group a valid sequence by constant blocks. If a prefix ends at value , then either it was all , or at some earlier position it transitioned from a proper divisor of into and then stayed there.
Let be the number of valid prefixes of length ending in . The recurrence has sums like . This screams for representing in the binomial basis , because prefix sums of binomial coefficients are clean.
Use . When propagating from divisor to multiple , coefficient adds to and subtracts from .
Sources checked: the official Codeforces statement and the official tutorial PDF. I did not find a useful public accepted-source mirror quickly, so the implementation below is derived from the official approach and verified against the canonical statement/samples.
First kill the annoying part of the constraints.
Since and all values are positive, we always have . So if a value is used at position , it must also be no larger than every later upper bound. Therefore we may replace
This is exact: every original valid sequence satisfies the tightened bound, and every sequence satisfying the tightened bound obviously satisfies the original bound. After this, is nondecreasing. Let , and for each value , define
So value is allowed exactly at positions .
Define as the number of valid prefixes ending with .
A valid prefix ending in has one of two forms:
For the transition to be legal, we need , allowed at position , and allowed at position . So define
Then for ,
Doing this directly is dead on arrival: too many positions, too many sums.
The trick is to store each in the binomial basis:
and before is allowed.
Why this basis? Because of the hockey-stick identity:
Since includes , the polynomial form for is valid throughout the summed range. So if contains the term , then its contribution to is
That means a transition from to does exactly this:
Also, if , add to for the all- sequence.
Process values . By the time we process , all its proper-divisor contributions are already done, because every proper divisor is smaller. Then propagate from to every multiple .
The number of useful coefficients is tiny. Every strict transition replaces a value by a proper multiple, so the value at least doubles. Thus a chain has at most strict transitions. With , storing about 20 coefficients is plenty. That’s the whole 2900-rated punchline: the DP looks huge, but the degree is capped by growth. Cute, and mildly evil.
Finally, every value is allowed at position , so the answer is
Edge cases:
Complexity:
There are divisor-to-multiple pairs, and coefficients per pair. So the total time is
with small constants. Memory is
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
const int MOD = 998244353;
const int K = 20;
int n;
cin >> n;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = n - 1; i >= 1; i--) a[i] = min(a[i], a[i + 1]);
int M = a[n];
vector<array<int, K + 1>> C(n + 1);
for (auto &row : C) row.fill(0);
C[0][0] = 1;
for (int i = 1; i <= n; i++) {
C[i][0] = 1;
for (int k = 1; k <= K; k++) {
C[i][k] = C[i - 1][k] + C[i - 1][k - 1];
if (C[i][k] >= MOD) C[i][k] -= MOD;
}
}
vector<int> left_pos(M + 1);
int p = 1;
for (int v = 1; v <= M; v++) {
while (a[p] < v) p++;
left_pos[v] = p;
}
vector<array<int, K + 1>> D(M + 1);
for (auto &row : D) row.fill(0);
auto addmod = [&](int &x, int y) {
x += y;
if (x >= MOD) x -= MOD;
};
auto submod = [&](int &x, int y) {
x -= y;
if (x < 0) x += MOD;
};
for (int u = 1; u <= M; u++) {
if (u <= a[1]) addmod(D[u][0], 1);
for (int v = u + u; v <= M; v += u) {
int L = max({1, left_pos[u], left_pos[v] - 1});
for (int k = 0; k < K; k++) {
int val = D[u][k];
if (!val) continue;
addmod(D[v][k + 1], val);
submod(D[v][0], (ll)val * C[L][k + 1] % MOD);
}
}
}
int ans = 0;
for (int v = 1; v <= M; v++) {
for (int k = 0; k <= K; k++) {
ans = (ans + (ll)D[v][k] * C[n][k]) % MOD;
}
}
cout << ans << '\n';
return 0;
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
const int MOD = 998244353;
const int K = 20;
int n;
cin >> n;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = n - 1; i >= 1; i--) a[i] = min(a[i], a[i + 1]);
int M = a[n];
vector<array<int, K + 1>> C(n + 1);
for (auto &row : C) row.fill(0);
C[0][0] = 1;
for (int i = 1; i <= n; i++) {
C[i][0] = 1;
for (int k = 1; k <= K; k++) {
C[i][k] = C[i - 1][k] + C[i - 1][k - 1];
if (C[i][k] >= MOD) C[i][k] -= MOD;
}
}
vector<int> left_pos(M + 1);
int p = 1;
for (int v = 1; v <= M; v++) {
while (a[p] < v) p++;
left_pos[v] = p;
}
vector<array<int, K + 1>> D(M + 1);
for (auto &row : D) row.fill(0);
auto addmod = [&](int &x, int y) {
x += y;
if (x >= MOD) x -= MOD;
};
auto submod = [&](int &x, int y) {
x -= y;
if (x < 0) x += MOD;
};
for (int u = 1; u <= M; u++) {
if (u <= a[1]) addmod(D[u][0], 1);
for (int v = u + u; v <= M; v += u) {
int L = max({1, left_pos[u], left_pos[v] - 1});
for (int k = 0; k < K; k++) {
int val = D[u][k];
if (!val) continue;
addmod(D[v][k + 1], val);
submod(D[v][0], (ll)val * C[L][k + 1] % MOD);
}
}
}
int ans = 0;
for (int v = 1; v <= M; v++) {
for (int k = 0; k <= K; k++) {
ans = (ans + (ll)D[v][k] * C[n][k]) % MOD;
}
}
cout << ans << '\n';
return 0;
}