原题链接
简洁题意:
给定一个 n n n,构造一个每个数都不大于 m m m,前 n n n个不下降,后 n n n个不上升,且 a x = a y a_x=a_y ax=ay的序列。注意,没有说 n n n是最高楼。
分析:
这个题可以发现,如果没有 a x = a y a_x=a_y ax=ay的要求就是分成前后两边,前面 n n n个不下降, m m m种高度看成盒子,要把 n n n个楼放进去。可以给每个盒子手动放一个球,就变成了插板法: C n + m − 1 m − 1 C_{n+m-1}^{m-1} Cn+m−1m−1就是答案。为了方便,后面的 F n m F_{n}^{m} Fnm表示 m m m种高度放 n n n个楼,即 C n + m − 1 m − 1 C_{n+m-1}^{m-1} Cn+m−1m−1。回到正题,我们这样放了前 n n n个楼,后面不上升的还有 n n n个楼,还是 m m m种高度可以选,则是 F n m F_{n}^{m} Fnm,两边的方案乘法原理乘起来即可。
考虑加上限制条件 a x = a y a_x=a_y ax=ay。第一种情况,分别处于 n n n的两边。则可以枚举它们两个的高度 h h h,分成四部分: ( 1 , x − 1 ) ( x + 1 , n ) ( n + 1 , y − 1 ) ( y + 1 , 2 ∗ n ) (1,x-1)(x+1,n)(n+1,y-1)(y+1,2*n) (1,x−1)(x+1,n)(n+1,y−1)(y+1,2∗n),方案数根据乘法原理是 F x − 1 h × F n − x m − h + 1 × F y − n − 1 m − h + 1 × F 2 × n − y h F_{x-1}^{h}\times F_{n-x}^{m-h+1}\times F_{y-n-1}^{m-h+1}\times F_{2\times n-y}^{h} Fx−1h×Fn−xm−h+1×Fy−n−1m−h+1×F2×n−yh。
那么考虑两个在同一边,则有一边是没有任何限制的, F n m F_n^m Fnm,另外一边不难发现, x x x和 y y y中间的楼都是等于 x x x和 y y y的。所以,把在外面的楼进行计算,把这些相同的也丢出去算,即 F n − x + y m F_{n-x+y}^m Fn−x+ym,这样就相当于把这些相同的压缩成一个点进行计算。
最后在考虑 C C C如何计算。因为题目要取模,所以不能用除法,于是只能乘逆元代替除法。则费马小定理出场了:
如果p是一个质数,则有 a p − 1 ≡ 1 ( m o d p ) a^{p-1}\equiv 1(modp) ap−1≡1(modp)
因此,有 a × a p − 2 ≡ 1 ( m o d p ) a\times a^{p-2}\equiv 1(modp) a×ap−2≡1(modp),所以 a p − 2 a^{p-2} ap−2就是 a a a的逆元。我们这个题模数刚好是质数,于是我们这个题就可以求出逆元来代替除法。因为这个题会算多次的 C C C,所以在前面会先初始化阶乘以及阶乘的逆元。
那么阶乘的逆元怎么求呢?其实也可以递推。 f i = f i + 1 × ( i + 1 ) f_i=f_{i+1}\times (i+1) fi=fi+1×(i+1),这个我就不证明了。所以,只用对最后一个计算快速幂后面递推计算即可。
最后, C C C怎么求呢? C n m = n ! ÷ m ! ÷ ( n − m ) ! C_n^m=n!\div m!\div (n-m)! Cnm=n!÷m!÷(n−m)!
这个题预处理是 Θ ( n ) \Theta(n) Θ(n)的,后面枚举了一下高度,时间复杂度 Θ ( m ) \Theta(m) Θ(m),但是如果是另一种情况时间复杂度又是 Θ ( 1 ) \Theta(1) Θ(1)的,所以时间复杂度是 O ( n + m ) O(n+m) O(n+m)的。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int NN=2e5+4,P=998244353;
ll m,n,x,y,ans,f1[NN],f2[NN];
ll ksm(ll a,ll b)
{
ll sum=1;
while(b)
{
if(b&1)
sum=sum*a%P;
a=a*a%P;
b>>=1;
}
return sum;
}
ll C(ll m,ll n)
{
return f1[n+m-1]*f2[n]%P*f2[m-1]%P;
}
int main()
{
scanf("%d%d%d%d",&m,&n,&x,&y);
f1[0]=1;
for(int i=1;i<=m+n;i++)
f1[i]=f1[i-1]*i%P;
f2[m+n]=ksm(f1[m+n],P-2);
for(int i=m+n-1;i>=0;i--)
f2[i]=f2[i+1]*(i+1)%P;
if(x<=n&&y>n)
for(int i=1;i<=m;i++)
ans=(ans+C(i,x-1)*C(m-i+1,n-x)%P*C(m-i+1,y-n-1)%P*C(i,2*n-y))%P;
else
ans=C(m,n)*C(m,n+x-y)%P;
printf("%d",ans);
return 0;
}