P8594
显然,肯定是由一堆横着的和一些竖着 \(2 \times 1\) 的构成的。而竖着的将将原来的网格分成了若干段。
先考虑只有一行,显然就是插板法。设长度为 \(n\),用了 \(m\) 块。答案就是 \(\dbinom {n-1} {m-1}\)。拓展到两个并列的一行,答案是 \(\dbinom {2n-2} {m-1}\)。感性理解,将两行放在一起,总共有 \(2n-2\) 个位置可以插(交界处不能插),要分成 \(m-1\) 块。要求多段,核心就是找到能插的个数和要划分的段数。
考虑枚举有 \(i\) 个竖着的,其中有 \(j\) 段。
先考虑剩下的分成 \(n-i\) 段的方案。要求方案数,首先我们要知道能插的个数。这是需要分类讨论。
- 若竖着没有在开头和结尾的,那么能插的个数为 \(2(n-1-i-j)\),还要划分的段数是 \(m-2(j+1)-i\),那么方案就是 \(\dbinom {2(n-1-i-j)} {m-2(j+1)-i}\)。
- 若竖着只有一个在开头结尾,那么能插的个数为 \(2(n-i-j)\),还要划分的段数是 \(m-2j-i\),那么方案就是 \(\dbinom {2(n-i-j)} {m-2j-i}\)。
- 若竖着的都在开头和结尾,那么能插的个数为 \(2(n+1-i-j)\),还要划分的段数是 \(m-2(j-1)-i\),那么方案就是 \(\dbinom {2(n+1-i-j)} {m-2(j-1)-i}\)。
接着考虑竖着的方案,发现这个直接用插板法很难求,那么考虑分步来求。先考虑划分为 \(j\) 段,这个直接插板求出,方案是 \(\dbinom {i-1} {j-1}\),再考虑把这 \(j\) 段再插到原来的网格中,可以插在剩下位置的前面,但是再第一个的前面就不行,所以方案是 \(\dbinom {n-i-1} {j/j-1/j-2}\),下面取决于上面的分裂讨论,那么总的方案就是乘积。
考虑枚举有 \(i\) 个竖着的,其中有 \(j\) 段的方案就是三种情况的和乘上竖着的方案。
#define fep(i,l,r) for(int i=l;i<=r;++i)
#define feb(i,r,l) for(int i=r;i>=l;--i)
#define For(i,u) for(int i=head[u];i;i=e[i].nxt)
#define pr pair<int,int>
#define mpr make_pair
#define LL long long
//#define int long long
using namespace std;
const int N = 4e7+5,M = 5e3+5,mod = 998244353;
int n,m,inv[N],fac[N],ifac[N],f[M];
inline int read()
{
int s=0,w=1; char ch=getchar();
while(!(ch<='9'&&ch>='0')) {if(ch=='-') w=-1; ch=getchar();}
while( ch<='9'&&ch>='0') {s=(s<<1)+(s<<3)+ch-'0'; ch=getchar();}
return s*w;
}
inline int Mod(int x) {return x>=mod?x-mod:x;}
inline void addmod(int &x,int y) {y<0?y+=mod:y=y; x=Mod(x+y);}
inline void init()
{
inv[1]=fac[0]=ifac[0]=1;
fep(i,1,2*n)
{
if(i^1) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
fac[i]=1ll*fac[i-1]*i%mod;
ifac[i]=1ll*ifac[i-1]*inv[i]%mod;
}
}
inline int C(int x,int y)
{
if(x<y) return 0;
return 1ll*fac[x]*ifac[y]%mod*ifac[x-y]%mod;
}
signed main()
{
n=read(),m=read();
init();
int ans=C(2*(n-1),m-2);
fep(i,1,m)
{
fep(j,1,i)
{
int tmp=j+1;
if(tmp*2+i<=m)
{
int now1=n-1-i-j,now2=m-(tmp*2+i);
int res=1ll*C(i-1,j-1)*C(n-i-1,j)%mod*C(2*now1,now2)%mod;
addmod(ans,res);
}
tmp=j;
if(tmp*2+i<=m)
{
int now1=n-i-j,now2=m-(tmp*2+i);
int res=2ll*C(i-1,j-1)*C(n-i-1,j-1)%mod*C(2*now1,now2)%mod;
addmod(ans,res);
}
tmp=j-1;
if(tmp*2+i<=m&&j>=2)
{
int now1=n+1-i-j,now2=m-(tmp*2+i);
int res=1ll*C(i-1,j-1)*C(n-i-1,j-2)%mod*C(2*now1,now2)%mod;
addmod(ans,res);
}
}
}
printf("%d\n",ans+(n==m));
return 0;
}

浙公网安备 33010602011771号