感觉这里把 \(a\) 的合法条件说清楚了。
考虑 \(c=2\),此时合法的 \(b\) 一定满足 \(b_i=2\) 的区间并不完全包含任何一个 \(b_i=1\) 的区间。
这样的 \(b\) 一定可以映射到一个 \(a\) 上,满足所有为 \(2\) 的极长段必须是某些段的并,我们直接处理出哪些区间是可以为某些段的并,直接设 \(f_{i,1/2}\) 转移即可。
考虑扩展到 \(c\) 为任意值的时候,此时我们考虑合法的 \(b\) 一定满足任意一个区间 \(i\),对于所有 \(b_j \gt b_i\) 的区间并一定不会全部被包含,然后将他区间内没有被 \(b_j \gt b_i\) 覆盖的点直接染成 \(b_i\)。
这样染色所对应的 \(a\) 一定满足:\(\forall x \in(1,c]\),颜色 \(\geq x\) 的极长段一定是某些区间的并。
考虑用区间 dp 刻画这个过程,设 \(f_{i,l,r}\) 表示在 \([l,r]\) 区间内填上 \([i,c]\) 颜色的方案数,设 \(w_{l,r}\) 表示其能否拆成一个区间。继承 \(f_{i+1}\) 的答案后,直接枚举该区间内第一个为 \(i\) 颜色的点即可。
观察数据范围不难想到可以用拉格朗日插值。
#include<bits/stdc++.h>
using namespace std;
#define N 105
#define p 998244353
#define ll long long
int n,m,k,L[N*N],R[N*N],w[N][N],vis[N];
ll f[N][N][N];
inline void upd(ll &x,ll y){(x+=y)%=p;}
inline ll qpow(ll a,int b){ll ans=1;for(;b;b>>=1,a=a*a%p)if(b&1)ans=ans*a%p;return ans;}
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=m;i++)scanf("%d%d",&L[i],&R[i]);
for(int l=1;l<=n;l++)for(int r=1;r<=n;r++){
memset(vis,0,sizeof(vis));w[l][r]=1;
for(int i=1;i<=m;i++)if(l<=L[i]&&R[i]<=r)++vis[L[i]],--vis[R[i]+1];
for(int i=l;i<=r;i++)vis[i]+=vis[i-1],w[l][r]&=(vis[i]!=0);
}
for(int c=1;c<=n+1;c++){
for(int r=1;r<=n;r++){
f[c][r][r]=w[r][r]*f[c-1][r][r]+1;
for(int l=r-1;l;l--){
f[c][l][r]=f[c-1][l][r]*w[l][r];
upd(f[c][l][r],f[c][l+1][r]);
upd(f[c][l][r],f[c-1][l][r-1]*w[l][r-1]);
for(int k=l+1;k<r;k++)
upd(f[c][l][r],f[c-1][l][k-1]*f[c][k+1][r]*w[l][k-1]%p);
}
}
}
if(k<=n+1)return printf("%lld",f[k][1][n]),0;
ll ans=0;
for(int i=1;i<=n+1;i++){
ll mul=1;
for(int j=1;j<=n+1;j++)if(i!=j)
mul=mul*(k-j)%p*qpow((i-j+p)%p,p-2)%p;
upd(ans,mul*f[i][1][n]%p);
}
printf("%lld\n",ans);
}