
本文共 3346 字,大约阅读时间需要 11 分钟。
题目
题目描述
今天,接触信息学不久的小 A A A刚刚学习了卡特兰数。
卡特兰数的一个经典定义是,将 n n n个数依次入栈,合法的出栈序列个数。
小 A A 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。
样例输入
3 12 3
样例输出
3
样例解释
可以验证 { 1 , 2 , 3 } \{1,2,3\} { 1,2,3}, { 2 , 1 , 3 } \{2,1,3\} { 2,1,3}, { 2 , 3 , 1 } \{2,3,1\} { 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 20 20 | ≤ 300 \le 300 ≤300 | ≤ 300 \le 300 ≤300 | |
6 6 6 | 20 20 20 | ≤ 300 \le 300 ≤300 |
对于全部的数据,保证 n ≤ 300 n\le 300 n≤300, m ≤ n ( n − 1 ) 2 m\le \frac{n(n-1)}{2} m≤2n(n−1), f i 、 g i ≤ n f_i、g_i \le n fi、gi≤n。
题解
题目大意: n n n个数以此入栈,问在满足 m m m个形如 f i f_i fi不能在 g i g_i gi后出栈的限制的出栈序列数
45%
我们知道卡特兰数有个推导公式是 f i = ∑ i = 1 n f i × f n − i − 1 f_i=\sum_{i=1}^nf_i\times f_{n-i-1} fi=∑i=1nfi×fn−i−1,这个公式实际上是枚举了最后出栈的数
那么扩展到这题,我们将 d p dp dp转换为区间 d p dp dp,枚举 k k k为最后出栈的数,那么有两种情况不合法: f = k f=k f=k或者 f > k > g f>k>g f>k>g。当 f = k f=k f=k的时候, f f f是最后出栈的,显然不合法。而我们知道,小于 k k k总是比大于 k k k的先出栈,所以当 f > k > g f>k>g f>k>g时也是不合法的
设 f [ i ] [ j ] f[i][j] f[i][j]表示 i i i到 j j j这个区间的合法出栈序列,那么在上述两种不合法的情况不成立的情况下, f [ i ] [ j ] + = f [ i ] [ k − 1 ] × f [ k + 1 ] [ j ] f[i][j]+=f[i][k-1]\times f[k+1][j] f[i][j]+=f[i][k−1]×f[k+1][j]
时间复杂度 O ( n 3 m ) O(n^3m) O(n3m),预计得分 45 45 45
100%
考虑优化 d p dp dp,在 O ( 1 ) O(1) O(1)的时间内判断合不合法。不合法条件 f > k > g f>k>g f>k>g成立,说明 f > g f>g f>g,那么在读入时 f > g f>g f>g的放入平面直角坐标系中,坐标 ( f , g ) (f,g) (f,g),那么可以前缀和优化
记录前缀和 s m [ i ] [ j ] sm[i][j] sm[i][j]和 l [ i ] [ j ] l[i][j] l[i][j],分别记录 f > g f>g f>g以及所有的点,用来判断 f > k > g f>k>g f>k>g和 f = k f=k f=k的情况
构造一个矩形
其中 i , j , k i,j,k i,j,k分别是区间起点,终点,以及最后出栈的数
f = k f=k f=k说明 l [ k ] [ j ] − l [ k ] [ i − 1 ] > 0 l[k][j]-l[k][i-1]>0 l[k][j]−l[k][i−1]>0,而如果矩形 s m ( i , i , j , k − 1 ) − s m ( i , i , k , j ) > 0 sm(i,i,j,k-1)-sm(i,i,k,j)>0 sm(i,i,j,k−1)−sm(i,i,k,j)>0,说明有 f > k > g f>k>g f>k>g的情况,这两种情况都是不合法的
这样的话时间复杂度优化到了 O ( n 3 ) O(n^3) O(n3),预计得分 100 100 100
Code
#include<cstdio>#define mod 998244353#define N 310#define ll long longusing namespace std;ll n,m,f[N][N],sm[N][N],al[N][N];ll get(ll x,ll y,ll p,ll q) { return sm[x][y]-sm[x][q-1]-sm[p-1][y]+sm[p-1][q-1];}int main(){ freopen("catalan.in","r",stdin); freopen("catalan.out","w",stdout); scanf("%lld%lld",&n,&m); for (ll i=1,x,y;i<=m;++i) { scanf("%lld%lld",&x,&y); if (x!=y) { if (x>y) ++sm[x][y]; ++al[x][y]; } } for (ll i=1;i<=n;++i) for (ll j=1;j<=n;++j) { sm[i][j]=sm[i][j]+sm[i-1][j]+sm[i][j-1]-sm[i-1][j-1]; al[i][j]=al[i][j]+al[i][j-1]; } for (ll i=1;i<=n;++i) f[i][i]=f[i+1][i]=f[i][i-1]=1; for (ll len=2;len<=n;++len) for (ll i=1;i+len-1<=n;++i) { ll j=i+len-1; for (ll k=i;k<=j;++k) { ll x; if (k>i) x=get(j,k-1,i,i)-get(k,j,i,i); else x=0; ll y=al[k][j]-al[k][i-1]; if (x<=0&&y<=0) f[i][j]=(f[i][j]+f[i][k-1]*f[k+1][j]%mod)%mod; } } printf("%lld\n",f[1][n]); fclose(stdin); fclose(stdout); return 0;}
发表评论
最新留言
关于作者
