You are given an array A of length n. You have to ...
Creado el: 12 de julio de 2025
Creado el: 12 de julio de 2025
You are given an array A of length n. You have to count the number of permutations p of the numbers 1 to n such that there are exactly k positions of i (1<=i<=n-1)
Where A[p[i]]<A[p[i+1]]
In other words you want to fknd permutations where A[p[i]] is smaller than A[p[i+1]] at exactly k different positions.
Give the result modulo 998244353
If all A[i]
are distinct, replacing every value with its rank (1 … n in increasing-A
order) doesn’t change any strict “ <
” comparisons.
After that replacement every permutation of indices becomes a permutation of the ranks 1 … n
, and
“
A[p[i]] < A[p[i+1]]
” ⇔ “ rank[p[i]] <
rank[p[i+1]]
”.
So we are counting permutations of 1 … n
having exactly k
ascents (positions where the sequence increases).
Those numbers are the classical Eulerian numbers ⟨ n, k
⟩.
⟨
n, k
⟩ = number of permutations ofn
with exactlyk
ascents.
They satisfy the recurrence
text⟨1,0⟩ = 1 ⟨n,k⟩ = (n-k)·⟨n-1,k-1⟩ + (k+1)·⟨n-1,k⟩ for 1 ≤ k ≤ n−1
Computing this for all k
up to n−1
takes O(n²) time and O(n) memory, perfectly fine for competitive-programming constraints (n ≤ 5 000, 10 000, …).
Everything is done modulo 998 244 353.
n, k
and the array A
.A
—the vast majority of tasks—skip this step.n
with the recurrence above.⟨n,k⟩ (mod 998 244 353)
; if k ≥ n
print 0.cpp#include <bits/stdc++.h> using namespace std; const int MOD = 998244353; int addmod(long long a){ return int(a%MOD); } int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); int n, k; // 1 ≤ n ≤ ? (problem limits) if(!(cin >> n >> k)) return 0; vector<long long> A(n); for(auto &x: A) cin >> x; // values are irrelevant if all distinct if(k >= n){ cout << 0 << '\n'; return 0; } vector<int> prev(n), cur(n); prev[0] = 1; // ⟨1,0⟩ for(int i = 2; i <= n; ++i){ fill(cur.begin(), cur.begin()+i, 0); for(int j = 0; j <= i-2; ++j){ // term (i-j)·⟨i-1,j⟩ → ascent count j+1 long long t1 = 1LL*(i - j)*prev[j] % MOD; cur[j+1] = (cur[j+1] + t1) % MOD; // term (j+1)·⟨i-1,j⟩ → ascent count stays j long long t2 = 1LL*(j + 1)*prev[j] % MOD; cur[j] = (cur[j] + t2) % MOD; } swap(prev, cur); } cout << prev[k] << '\n'; return 0; }
Complexities
step | time | memory |
---|---|---|
DP | O(n²) | O(n) |
total | O(n²) | O(n) |
A
may contain duplicates?Then we are counting permutations of multisets with a given number of strict ascents—a “multiset Eulerian” problem. A workable approach is:
s₁, s₂, …
.dp[len][asc]
= ways after placing the first len
elements,(small → large)
transitions are created.O(n log² n)
.Because this requires a longer derivation, most contest setters phrase the task with distinct A[i]
, in which case the simple Eulerian solution above is accepted and optimal.