https://codeforces.com/contest/1913/problem/D
题目大意
给出一个 $n \ (1 \le n \le 3 \times 10^5)$ 排列 $p$。可以做如下操作任意次:
选出一个区间 $[l, r]$ 将其中除了最小元素以外的元素全部删掉。
问结果数组共有多少种。结果对 $998244353$ 取模。
简要题解
观察:
- 注意到 $1$ 永远删不掉。
- 考虑 $2$ 则如果想删掉 $2$ 只能靠选一个包含 $1, 2$ 的数组。也就是说如果结果中没有 $2$ 则也没有 $1, 2$ 之间的所有其他数。
- 对于 $i$ 我们找到其左右比它更大的最近的数,如果想删掉它,只能靠至少包含这两个数其中之一的数,如果某一侧没有比它更大的数,则无法通过这一侧将其删去。
- $2$ 对于越过 $1$ 的另一侧的数是没影响的。因为这样总会越过 $1$ 而有 $1$ 就够了。
- 扩展到更多的数,越过比它自己更大的数的区间是没有意义的。
这样其实我们已经知道了该如何算。由 $5$ 可知我们其实可以从小到大的分割处理区间。对于当前的区间 $l, r$ 我们找出其中最小的元素 $i$。 保留 $i$,则其实 $i$ 这里类似于 $1$ 对于整个数组,递归进入左右区间即可。 要删掉 $i$ 我们总要删掉其中一边,或者我们把两边数组都删掉(这是可以行的,因为可以先通过 $i$ 删掉一边,再通过 $i$ 和另一边更小的数 ($l, r$ 边界之外的数)来删掉 $i$)。
复杂度
$T$:$O(n \log n)$
$S$:$O(n \log n)$ 因为用了 sparse-table。
代码实现
#include <bits/stdc++.h>
using namespace std;
int io_=[](){ ios::sync_with_stdio(false); cin.tie(nullptr); return 0; }();
using LL = long long;
using ULL = unsigned long long;
using LD = long double;
using PII = pair<int, int>;
using VI = vector<int>;
using MII = map<int, int>;
template<typename T> void cmin(T &x,const T &y) { if(y<x) x=y; }
template<typename T> void cmax(T &x,const T &y) { if(x<y) x=y; }
template<typename T> bool ckmin(T &x,const T &y) {
return y<x ? (x=y, true) : false; }
template<typename T> bool ckmax(T &x,const T &y) {
return x<y ? (x=y, true) : false; }
template<typename T> void cmin(T &x,T &y,const T &z) {// x<=y<=z
if(z<x) { y=x; x=z; } else if(z<y) y=z; }
template<typename T> void cmax(T &x,T &y,const T &z) {// x>=y>=z
if(x<z) { y=x; x=z; } else if(y<z) y=z; }
// mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
// mt19937_64 rnd_64(chrono::system_clock::now().time_since_epoch().count());
template<typename T, typename CMP=less<T>>
struct SparseTable {
constexpr static CMP cmp{};
static T min(const T& a, const T& b) { return (cmp(a, b) ? a : b); }
static int lg(int x) { return 31 - __builtin_clz(x); }
vector<vector<T> > st;
SparseTable(const vector<T>& a) {
int n = a.size();
int b = lg(n);
st.push_back(a);
for (int i = 1; i <= b; i++) {
int m = n - (1 << i) + 1;
vector<T> b(m);
for (int j = 0; j < m; j++) {
b[j] = min(st[i - 1][j], st[i - 1][j + (1 << (i - 1))]);
}
st.push_back(b);
}
}
T query(int l, int r) {
int i = lg(r - l + 1);
return min(st[i][l], st[i][r - (1 << i) + 1]);
}
};
template<typename Func> struct YCombinatorResult {
Func func;
template<typename T>
explicit YCombinatorResult(T &&func) : func(std::forward<T>(func)) {}
template<class ...Args> decltype(auto) operator()(Args &&...args) {
return func(std::ref(*this), std::forward<Args>(args)...);
}
};
template<typename Func> decltype(auto) y_comb(Func &&fun) {
return YCombinatorResult<std::decay_t<Func>>(std::forward<Func>(fun));
}
template<long long Mo=998244353> struct ModInt {
static long long MO;
static void setMo(long long mo) { MO = mo; }
long long x;
ModInt(long long x=0) : x(x){ norm(); }
friend istream &operator>>(istream& in, ModInt &B) { in>>B.x; return in; }
friend ostream &operator<<(ostream& out, const ModInt &B) {
out<<B.x; return out; }
// ModInt operator=(int x_) { x=x_; norm(); return *this; }
void norm() { x = (x%MO + MO) % MO; }
long long get() { return x; }
ModInt operator-() const { return ModInt(MO - x); }
ModInt operator+=(const ModInt &B) { x+=B.x; if(x>=MO) x-=MO; return *this; }
ModInt operator-=(const ModInt &B) { x-=B.x; if(x<0) x+=MO; return *this; }
ModInt operator*=(const ModInt &B) { x=x*B.x%MO; return *this; }
ModInt operator+(const ModInt &B) const { ModInt ans=*this; return ans+=B; }
ModInt operator-(const ModInt &B) const { ModInt ans=*this; return ans-=B; }
ModInt operator*(const ModInt &B) const { ModInt ans=*this; return ans*=B; }
ModInt operator^(long long n) const {
ModInt a=*this; ModInt ans(1);
while(n) { if(n&1) ans*=a; a*=a; n>>=1; }
return ans;
}
ModInt inv() const { return (*this)^(MO-2); } // if MO is prime
ModInt operator/=(const ModInt &B) { (*this)*=B.inv(); return *this; }
ModInt operator/(const ModInt &B) const { ModInt ans=*this; return ans/=B; }
bool operator<(const ModInt &B) const { return x<B.x; }
bool operator==(const ModInt &B) const { return x==B.x; }
bool operator!=(const ModInt &B) const { return x!=B.x; }
};
template<long long Mo> long long ModInt<Mo>::MO = Mo;
typedef ModInt<998244353> Mint;
// typedef ModInt<1'000'000'007> Mint;
/*
---------1---------2---------3---------4---------5---------6---------7---------
1234567890123456789012345678901234567890123456789012345678901234567890123456789
*/
void solve() {
int n; cin >> n;
vector<PII> p(n);
for (int i = 0; i < n; i++) {
cin >> p[i].first;
p[i].second = i;
}
SparseTable st(p);
Mint ans = y_comb([&](auto dfs, int l, int r) -> Mint {
if (l == r) {
Mint ans = 1; // keep
if (l || r < n - 1) ans += 1; // remove with left or right
return ans;
}
int mid = st.query(l, r).second;
Mint lans = (l < mid ? dfs(l, mid - 1) : Mint(1));
Mint rans = (mid < r ? dfs(mid + 1, r) : Mint(1));
Mint ans = lans * rans; // keep
if (l) ans += (rans - 1); // remove left
if (r < n - 1) ans += (lans - 1); // remove right
if (l || (r < n - 1)) ans += 1; // remove both
return ans;
})(0, n - 1);
cout << ans << '\n';
}
int main() {
int t = 1;
cin >> t;
while (t--) {
solve();
}
return 0;
}
Next: [CF] C. Game with Multiset - Educational Codeforces Round 160 (Rated for Div. 2)