[ARC186B] Typical Permutation Descriptor
这道题挺好的。
容易发现 \(a_i\) 就是第一个比第 \(i\) 个位置小的数,所以我们能够发现这个序列的笛卡尔树是唯一的。
然后就简单了,笛卡尔树的结构确定,每个节点的左右儿子中的值互不影响,于是就有转移式: \(dp_{l,r} = dp_{l,pos-1} \times dp_{pos+1,r} \times \binom{r-l}{pos-l}\), \(pos\) 指的是笛卡尔树上的当前节点位置,然后就做完了。
点击查看代码
#include<bits/stdc++.h>
#define fir first
#define sec second
#define int long long
#define lowbit(x) x&(-x)
#define mkp(a,b) make_pair(a,b)
using namespace std;
typedef pair<int,int> pir;
inline int read(){
int x=0,f=1; char c=getchar();
while(!isdigit(c)){if(c=='-') f=-1; c=getchar();}
while(isdigit(c)){x=x*10+(c^48); c=getchar();}
return x*f;
}
const int inf=1e18,N=3e5+5,mod=998244353;
int n;
int a[N];
int jie[N],invj[N],inv[N];
vector<int> e[N];
inline void init(){
jie[0]=invj[0]=jie[1]=invj[1]=inv[1]=1;
for(int i=2;i<=n;i++)
jie[i]=jie[i-1]*i%mod,
inv[i]=(mod-mod/i)*inv[mod%i]%mod,
invj[i]=invj[i-1]*inv[i]%mod;
}
inline int C(int x,int y){
if(x<y) return 0;
return jie[x]*invj[y]%mod*invj[x-y]%mod;
}
inline int solve(int l,int r,int num){
if(l>=r) return 1;
auto it=upper_bound(e[num].begin(),e[num].end(),r);
it--;
int pos=*it;
return solve(l,pos-1,num)*solve(pos+1,r,pos)%mod*C(r-l,pos-l)%mod;
}
signed main(){
n=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n;i++) e[a[i]].push_back(i);
init();
cout<<solve(1,n,0)<<'\n';
}