今天,接触信息学不久的小 A
刚刚学习了卡特兰数。
卡特兰数的一个经典定义是,将 n n n 个数依次入栈,合法的出栈序列个数。
小 A
觉得这样的情况太平凡了。于是,他给出了
m
m
m 组限制,每个限制形如
(
f
i
,
g
i
)
(f_i,g_i)
(fi,gi),表示
f
i
f_i
fi 不能在
g
i
g_i
gi 之后出栈。
他想求出:在满足了这 m m m 组限制的前提下,共有多少个合法的出栈序列。他不喜欢大数,你只需要求出答案在模 998244353 998244353 998244353 意义下的值即可。
输入第一行为两个非负整数, n n n、 m m m,含义题面已给出。
接下来 m m m 行,每行两个正整数, ( f , g ) (f,g) (f,g) 表示一组限制。
输出一行,为一个非负整数,表示你求得的答案 m o d 998244353 mod\space 998244353 mod 998244353。
样例输入1
3 1
2 3
样例输出1
3
样例1解释
可以验证 { 1 , 2 , 3 } , { 2 , 1 , 3 } , { 2 , 3 , 1 } \{1,2,3\},\{2,1,3\},\{2,3,1\} {1,2,3},{2,1,3},{2,3,1} 都是合乎条件的。
编号 | 分值 | n n n | m m m | 特殊性质 |
---|---|---|---|---|
1 1 1 | 15 15 15 | ≤ 300 \le 300 ≤300 | = 0 = 0 =0 | − - − |
2 2 2 | 15 15 15 | ≤ 7 \le 7 ≤7 | ≤ 10 \le 10 ≤10 | − - − |
3 3 3 | 15 15 15 | ≤ 100 \le 100 ≤100 | ≤ 50 \le 50 ≤50 | − - − |
4 4 4 | 15 15 15 | ≤ 300 \le 300 ≤300 | − - − | 保证所有的 f i f_i fi 相同 |
5 5 5 | $ 20$ | ≤ 300 \le 300 ≤300 | ≤ 300 \le 300 ≤300 | − - − |
6 6 6 | 20 20 20 | ≤ 300 \le 300 ≤300 | − - − | − - − |
对于全部的数据,保证 n ≤ 300 , m ≤ n ( n − 1 ) 2 , f i , g i ≤ n n\le 300,m\le \frac{n(n-1)}{2},f_i,g_i \le n n≤300,m≤2n(n−1),fi,gi≤n
YALI noip2020 模拟
考虑普通卡特兰数
D
P
DP
DP,即枚举区间最晚出栈的数。
那么对于这道题,发现只需要在区间
D
P
DP
DP 时限制转移,即
f
i
f_i
fi 比
g
i
g_i
gi 先出即可。
#include<bits/stdc++.h>
#define N 305
typedef long long ll;
using namespace std;
const ll mod=998244353;
inline int read() {
char ch;
while(!isdigit(ch=getchar()));
int sum=ch^48;
while(isdigit(ch=getchar()))sum=(sum<<1)+(sum<<3)+(ch^48);
return sum;
}
vector<int> to[N];
ll f[N][N],b[N];
int main(){
int n=read(),m=read();
for(int i=1;i<=m;++i){
int f=read(),g=read();
if(f!=g)to[f].push_back(g);
}
for(int i=1;i<=n;++i){
to[i].push_back(0);to[i].push_back(n+1);
sort(to[i].begin(),to[i].end());
f[i][i]=1;f[i][i-1]=1;f[i+1][i]=1;
}
for(int len=2;len<=n;++len){
for(int i=1;i<=n-len+1;++i){
int j=i+len-1,maxn=i;
for(int k=i;k<=j;++k){
int lpos=lower_bound(to[k].begin(),to[k].end(),i)-to[k].begin();
if(lpos!=to[k].size()&&to[k][lpos]<k){
--b[to[k][lpos]+1];++b[k+1];
}else{
if(lpos!=to[k].size()&&to[k][lpos]<=j){
--b[k];++b[k+1];
}
}
}
for(int k=i;k<=j;++k){
b[k]+=b[k-1];
if(b[k]>=0){
f[i][j]=(f[i][j]+f[i][k-1]*f[k+1][j]%mod)%mod;
}
}
for(int k=1;k<=n;++k)b[k]=0;
}
}
printf("%lld\n",(f[1][n]+mod)%mod);
return 0;
}