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.
Since and can never be the median of any triple, distinctness means must contain every value exactly once.
If two triples have the same median value, that value's position must lie in both triples. So any duplicate median is local: the two starting indices differ by at most . Length- windows are where the whole monster hides.
Look at positions with the same parity. If , then must be . Similarly, if , then must be .
So each parity subsequence is almost monotone, with possible turning points only at the positions of and . The interaction between the two parities is also forced by four consecutive positions where one parity goes up and the other goes down.
After fixing the positions of and , all valid permutations are exactly assignments of values into at most two increasing chains. Count the assignments by scanning fixed values in increasing order and multiplying binomial coefficients for the gaps.
Use 0-indexed positions. Put a directed edge to mean .
First, get rid of a tempting but useless idea: do not try to DP the medians directly. The medians are a symptom. The real structure is in the order relations between positions.
There are medians, and neither nor can ever be a median. Therefore, if all medians are distinct, then is exactly the set .
Now two local facts do basically all the work.
First, if , the equal value appears in both triples, so the triples must share its position. Thus . Any duplicate median is visible inside some length- block.
Second, consider a center with both and present. If
,
then must be . Suppose not. If , then the triple has median . To avoid also making have median , we need . But then has median anyway. Same argument from the other side. So both neighbors and must be smaller than , meaning is never a median in any triple containing it. Since is not or , impossible. Hence . The valley case is symmetric: if , then .
So along each parity, the comparisons can only turn at the positions of and . That is already a huge collapse.
We also need to understand how the two parities compare. For four consecutive positions with values , suppose and . The two triples are and . A short rank check gives only two valid orders:
In plain English: when one parity rises and the other falls, one whole parity-pair must sit below the other. No partial crossing allowed. Crossings are how duplicate medians sneak in and ruin your day.
Now assume the position of is before the position of ; if not, reverse the whole array. Reversal is a bijection and preserves the distinctness condition.
Build the forced inequality graph like this.
If pos1 and posn have the same parity:
If pos1 and posn have different parity:
Finally add the two bridge inequalities forced by the four-position rule near the ends:
pos1 != 0, add when pos1 is even, otherwise ;posn != 0, add when posn has the same parity as , otherwise .Then remove the outgoing edge from the actual position of , and remove every edge going into the actual position of . We treat and as virtual endpoints, not normal chain elements.
The graph becomes at most two increasing chains. Every valid permutation must respect these chains by the local facts above. Conversely, if values increase along these chains, every length- window has one of the valid local rank patterns, so no duplicate median appears. Since duplicates are local, that is sufficient.
Now counting is clean.
Once we know which values belong to each chain, the actual placement is forced: each chain receives its chosen values in increasing order. So the only choice is the chain membership of each currently unknown value.
During chain traversal, store where[x] = (chain, index) for each fixed value . Also store virtual as the first element of chain , and virtual as the element after the last real element of the last chain.
For a fixed left value , define left as the number of values in chain among :
left = c+1;left = x-(c+1).For the next fixed value , define right as the number of values in chain among :
right = c;right = y-1-c.The values are all unfixed. There are of them, and exactly right-left must go to chain . So this gap contributes
.
Multiply this over all consecutive fixed values. If a fixed constraint is impossible, the binomial has an invalid lower argument and contributes .
Edge cases are handled naturally: no unknown values means all gaps have size ; adjacent and may produce only one real chain; fixed values contradicting the chain order produce answer .
Precompute factorials and inverse factorials. The graph construction and counting are linear, so the total complexity is per test case after precomputation, with memory.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
const int MOD = 998244353;
const int MAXN = 200000 + 5;
struct Mint {
int v;
Mint(long long x = 0) {
x %= MOD;
if (x < 0) x += MOD;
v = int(x);
}
Mint& operator+=(const Mint& other) {
v += other.v;
if (v >= MOD) v -= MOD;
return *this;
}
Mint& operator-=(const Mint& other) {
v -= other.v;
if (v < 0) v += MOD;
return *this;
}
Mint& operator*=(const Mint& other) {
v = int((ll)v * other.v % MOD);
return *this;
}
friend Mint operator+(Mint a, const Mint& b) { return a += b; }
friend Mint operator-(Mint a, const Mint& b) { return a -= b; }
friend Mint operator*(Mint a, const Mint& b) { return a *= b; }
};
Mint modPow(Mint a, long long e) {
Mint r = 1;
while (e) {
if (e & 1) r *= a;
a *= a;
e >>= 1;
}
return r;
}
vector<Mint> fact(MAXN), invFact(MAXN);
Mint C(int n, int k) {
if (n < 0 || k < 0 || k > n) return 0;
return fact[n] * invFact[k] * invFact[n - k];
}
Mint countWays(vector<int> p) {
int n = int(p.size());
int pos1 = -1, posn = -1;
for (int i = 0; i < n; i++) {
if (p[i] == 1) pos1 = i;
if (p[i] == n) posn = i;
}
if (pos1 > posn) {
reverse(p.begin(), p.end());
pos1 = n - 1 - pos1;
posn = n - 1 - posn;
}
vector<vector<int>> g(n);
if (pos1 % 2 == posn % 2) {
for (int i = ((pos1 & 1) ^ 1); i < n; i += 2) {
if (i >= 2) g[i - 2].push_back(i);
}
for (int i = pos1 - 2; i >= 0; i -= 2) g[i + 2].push_back(i);
for (int i = pos1 + 2; i <= posn; i += 2) g[i - 2].push_back(i);
for (int i = posn + 2; i < n; i += 2) g[i].push_back(i - 2);
} else {
for (int i = pos1 - 2; i >= 0; i -= 2) g[i + 2].push_back(i);
for (int i = pos1 + 2; i < n; i += 2) g[i - 2].push_back(i);
for (int i = posn - 2; i >= 0; i -= 2) g[i].push_back(i + 2);
for (int i = posn + 2; i < n; i += 2) g[i].push_back(i - 2);
}
if (pos1 != 0) {
if (pos1 % 2 == 0) g[0].push_back(1);
else g[1].push_back(0);
}
if (posn != 0) {
if (posn % 2 == (n - 1) % 2) g[n - 2].push_back(n - 1);
else g[n - 1].push_back(n - 2);
}
g[pos1].clear();
for (int i = 0; i < n; i++) {
if (i == pos1 || i == posn) continue;
if (g[i].size() != 1) return 0;
if (g[i][0] == posn) g[i].clear();
}
vector<int> indeg(n, 0);
for (int v = 0; v < n; v++) {
for (int to : g[v]) indeg[to]++;
}
vector<pair<int, int>> where(n + 1, {0, 0});
int chains = 0, cnt = 0;
for (int start = 0; start < n; start++) {
if (start == pos1 || start == posn || indeg[start] > 0) continue;
chains++;
cnt = 0;
if (chains == 1) where[1] = {chains, cnt++};
int v = start;
while (true) {
if (p[v] != 0) where[p[v]] = {chains, cnt};
cnt++;
if (g[v].empty()) break;
v = g[v][0];
}
}
where[n] = {chains, cnt};
Mint ans = 1;
for (int x = 1; x < n; ) {
int y = x + 1;
while (y <= n && where[y].first == 0) y++;
auto [chx, ix] = where[x];
auto [chy, iy] = where[y];
if (chx == 0 || chy == 0 || chx > 2 || chy > 2) return 0;
int left = (chx == 1 ? ix + 1 : x - (ix + 1));
int right = (chy == 1 ? iy : y - 1 - iy);
ans *= C(y - x - 1, right - left);
x = y;
}
return ans;
}
int main() {
setIO();
fact[0] = 1;
for (int i = 1; i < MAXN; i++) fact[i] = fact[i - 1] * i;
invFact[MAXN - 1] = modPow(fact[MAXN - 1], MOD - 2);
for (int i = MAXN - 1; i > 0; i--) invFact[i - 1] = invFact[i] * i;
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<int> a(n);
for (int& x : a) cin >> x;
cout << countWays(a).v << char(10);
}
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
const int MOD = 998244353;
const int MAXN = 200000 + 5;
struct Mint {
int v;
Mint(long long x = 0) {
x %= MOD;
if (x < 0) x += MOD;
v = int(x);
}
Mint& operator+=(const Mint& other) {
v += other.v;
if (v >= MOD) v -= MOD;
return *this;
}
Mint& operator-=(const Mint& other) {
v -= other.v;
if (v < 0) v += MOD;
return *this;
}
Mint& operator*=(const Mint& other) {
v = int((ll)v * other.v % MOD);
return *this;
}
friend Mint operator+(Mint a, const Mint& b) { return a += b; }
friend Mint operator-(Mint a, const Mint& b) { return a -= b; }
friend Mint operator*(Mint a, const Mint& b) { return a *= b; }
};
Mint modPow(Mint a, long long e) {
Mint r = 1;
while (e) {
if (e & 1) r *= a;
a *= a;
e >>= 1;
}
return r;
}
vector<Mint> fact(MAXN), invFact(MAXN);
Mint C(int n, int k) {
if (n < 0 || k < 0 || k > n) return 0;
return fact[n] * invFact[k] * invFact[n - k];
}
Mint countWays(vector<int> p) {
int n = int(p.size());
int pos1 = -1, posn = -1;
for (int i = 0; i < n; i++) {
if (p[i] == 1) pos1 = i;
if (p[i] == n) posn = i;
}
if (pos1 > posn) {
reverse(p.begin(), p.end());
pos1 = n - 1 - pos1;
posn = n - 1 - posn;
}
vector<vector<int>> g(n);
if (pos1 % 2 == posn % 2) {
for (int i = ((pos1 & 1) ^ 1); i < n; i += 2) {
if (i >= 2) g[i - 2].push_back(i);
}
for (int i = pos1 - 2; i >= 0; i -= 2) g[i + 2].push_back(i);
for (int i = pos1 + 2; i <= posn; i += 2) g[i - 2].push_back(i);
for (int i = posn + 2; i < n; i += 2) g[i].push_back(i - 2);
} else {
for (int i = pos1 - 2; i >= 0; i -= 2) g[i + 2].push_back(i);
for (int i = pos1 + 2; i < n; i += 2) g[i - 2].push_back(i);
for (int i = posn - 2; i >= 0; i -= 2) g[i].push_back(i + 2);
for (int i = posn + 2; i < n; i += 2) g[i].push_back(i - 2);
}
if (pos1 != 0) {
if (pos1 % 2 == 0) g[0].push_back(1);
else g[1].push_back(0);
}
if (posn != 0) {
if (posn % 2 == (n - 1) % 2) g[n - 2].push_back(n - 1);
else g[n - 1].push_back(n - 2);
}
g[pos1].clear();
for (int i = 0; i < n; i++) {
if (i == pos1 || i == posn) continue;
if (g[i].size() != 1) return 0;
if (g[i][0] == posn) g[i].clear();
}
vector<int> indeg(n, 0);
for (int v = 0; v < n; v++) {
for (int to : g[v]) indeg[to]++;
}
vector<pair<int, int>> where(n + 1, {0, 0});
int chains = 0, cnt = 0;
for (int start = 0; start < n; start++) {
if (start == pos1 || start == posn || indeg[start] > 0) continue;
chains++;
cnt = 0;
if (chains == 1) where[1] = {chains, cnt++};
int v = start;
while (true) {
if (p[v] != 0) where[p[v]] = {chains, cnt};
cnt++;
if (g[v].empty()) break;
v = g[v][0];
}
}
where[n] = {chains, cnt};
Mint ans = 1;
for (int x = 1; x < n; ) {
int y = x + 1;
while (y <= n && where[y].first == 0) y++;
auto [chx, ix] = where[x];
auto [chy, iy] = where[y];
if (chx == 0 || chy == 0 || chx > 2 || chy > 2) return 0;
int left = (chx == 1 ? ix + 1 : x - (ix + 1));
int right = (chy == 1 ? iy : y - 1 - iy);
ans *= C(y - x - 1, right - left);
x = y;
}
return ans;
}
int main() {
setIO();
fact[0] = 1;
for (int i = 1; i < MAXN; i++) fact[i] = fact[i - 1] * i;
invFact[MAXN - 1] = modPow(fact[MAXN - 1], MOD - 2);
for (int i = MAXN - 1; i > 0; i--) invFact[i - 1] = invFact[i] * i;
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<int> a(n);
for (int& x : a) cin >> x;
cout << countWays(a).v << char(10);
}
}