[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';
}
posted @ 2024-11-27 08:01  ~Cyan~  阅读(2)  评论(0编辑  收藏  举报