# ARC183-C Not Argmax
2018diff
https://atcoder.jp/contests/arc183/tasks/arc183_c
## 解法
適切に前計算を行っておくことで、「$N$をおいてはいけない場所」がわかる。$N$を置いて良い場所を一つ固定して($i$)、そこに$N$を置いたとする。そうすると$L_{j}\le i\le R_{j}$なる区間の条件はすべて無視して良いことになる。なぜならそのような区間の$\text{argmax}$は$\{ i\}$だから。
結局の所$i$を固定すると$(P_{1}, P_{2}, \dots, P_{i - 1})$と$(P_{i + 1}, P_{i + 2}, \dots, P_{N})$それぞれについて同様の問題を解くことに帰着する。これは区間DPをやれば良いという兆し。
DPの計算と入力を受け取るのがボトルネックで、 $\Theta (N^{3} + M)$
## 実装
```cpp=
#include <bits/stdc++.h>
const long long MOD{998244353};
const int MAX{510};
long long comb[MAX][MAX];
long long add(long long a, long long b) {
a += b;
if (a >= MOD) a -= MOD;
return a;
}
long long mul(long long a, long long b) {
return a * b % MOD;
}
int main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
for (int i{} ; i < MAX ; i++) comb[i][0] = comb[i][i] = 1;
for (int i{1} ; i < MAX ; i++) for (int j{1} ; j < i ; j++)
comb[i][j] = add(comb[i - 1][j - 1], comb[i - 1][j]);
int N, M;
std::cin >> N >> M;
std::vector ng(N, std::vector(N + 1, std::vector<bool>(N)));
for (int i{} ; i < M ; i++) {
int L, R, X;
std::cin >> L >> R >> X;
L--; X--;
ng[L][R][X] = true;
}
for (int len{1} ; len <= N ; len++) {
for (int l{} ; l + len <= N ; l++) {
int r{l + len};
if (l) {
for (int i{l} ; i < r ; i++) ng[l - 1][r][i] = ng[l - 1][r][i] | ng[l][r][i];
}
if (r < N) {
for (int i{l} ; i < r ; i++) ng[l][r + 1][i] = ng[l][r + 1][i] | ng[l][r][i];
}
}
}
std::vector dp(N + 1, std::vector<long long>(N + 1, -1LL));
auto rec{[&](auto rec, int l, int r) -> long long {
if (dp[l][r] != -1) return dp[l][r];
long long& res{dp[l][r]};
res = 0;
if (l == r) return res = 1;
for (int m{l} ; m < r ; m++) if (!ng[l][r][m]) {
res = add(res, mul(rec(rec, l, m), mul(rec(rec, m + 1, r), comb[r - l - 1][m - l])));
}
return res;
}};
std::cout << rec(rec, 0, N) << '\n';
}
```
[提出](https://atcoder.jp/contests/arc183/submissions/58390369)
## 感想
この回はコンテストにオンタイムで参加していて、$120$分ほぼ全部これにつっぱして解けなかった思い出がある。感想戦で方針を知っていた。
当時は包除原理ばっかり考えていて詰んでいた。変に解法をエスパーするよりも、堅実に観察・定式化を積み上げる考察を心がけたいものだ。