*题解:[ABC478F] Min-First Search
解析
确定儿子发现不好做,因为一个儿子被一个点选为儿子了就不能被另一个点选为儿子,且无法确定儿子个数。找父亲就没有这些问题了,一个点的父亲只有一个,且选中父亲不会影响到其它点。
观察一下什么点能成为 \(Q_i\) 的父亲,发现左边的一个极长的段内元素大小小于 \(Q_i\) 的连续段合法。然后遇到第一个大于 \(Q_i\) 的 \(Q_j\),发现这个应该也合法。但再往左就不合法了,因为如果选取了 \(k < j\) 的 \(Q_k\)为父亲,那么当 \(Q_k\) 被从 \(S\) 中取出时,\(Q_i\) 会加入 \(S\),又因为 \(Q_i < Q_j\),故 \(Q_i\) 会先于 \(Q_j\) 取出,与 \(i > j\) 矛盾。
故使用单调栈求每个数左侧第一个比它大的数的位置,这之间的数都可选,把距离乘起来即可。
时间复杂度 \(O(n)\)。
没想到的地方
找父亲。
总结
对于树上问题,由于儿子可能有很多,但父亲只能有一个,可以尝试从儿子的角度看父亲来解决问题。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 2e5,M = 16 + 2,V = 3000,mod = 998244353;
int q[N];
stack<int> s;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>q[i];
}
int res = 1;
for(int i=n;i>=1;i--){
while(!s.empty() && q[i] > q[s.top()]){
res = 1ll * res * (s.top() - i) % mod;
s.pop();
}
s.push(i);
}
while(!s.empty()){
res = 1ll * res * max(1,s.top() - 1) % mod;
s.pop();
}
cout<<res;
return 0;
}

浙公网安备 33010602011771号