题目:
题解:
又是上下左右走的问题。。。当初我的Catalan入门就是这玩意
那么我们设g[i]表示走i步光走左右不走上下,不会不走,回到原点的方案数
可以发现当i为奇数的时候g[i]=0
考虑i为偶数的情况,肯定是选择i/2步向上走,i/2步向下走,并且时刻保证向上走的步数>=向下走的步数
这不就是Catalan数吗,可以用
Ci/2i−Ci/2−1i
C
i
i
/
2
−
C
i
i
/
2
−
1
求解
显然光走上下不走左右,不会不走,回到原点的方案也是g[i]
现在我们设f[i]表示走i步,可以走上下左右,不会不走,回到原点的方案数
那么
f[i]=∑ij=0g(j)∗g(i−j)∗Cji
f
[
i
]
=
∑
j
=
0
i
g
(
j
)
∗
g
(
i
−
j
)
∗
C
i
j
我们把组合数展开
卷积!又看到了熟悉的模数,NTT吧
那么如果有不走的情况呢? ans=∑ni=0f[i]∗Cin a n s = ∑ i = 0 n f [ i ] ∗ C n i
代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#define LL long long
using namespace std;
const int mod=998244353;
const int N=400005;
LL a[N],b[N],mul[N],inv[N],invmul[N],g[N];int r[N],n;
LL ksm(LL a,LL k)
{
LL ans=1;
for (;k;k>>=1,a=a*a%mod)
if (k&1) ans=ans*a%mod;
return ans;
}
void NTT(LL *a,int id)
{
for (int i=0;i<n;i++)
if (i<r[i]) swap(a[i],a[r[i]]);
for (int k=1;k<n;k<<=1)
{
LL wn=ksm(3,(mod-1)/(k<<1));
for (int i=0;i<n;i+=(k<<1))
{
LL w=1;
for (int j=0;j<k;j++,w=w*wn%mod)
{
LL x=a[i+j],y=w*a[i+j+k]%mod;
a[i+j]=(x+y)%mod; a[i+j+k]=(x-y+mod)%mod;
}
}
}
if (id==-1) reverse(a+1,a+n);
}
LL C(int n,int m)
{
if (m>n) return 0;
return mul[n]*invmul[m]%mod*invmul[n-m]%mod;
}
void init(int n)
{
mul[0]=mul[1]=1;
for (int i=2;i<=n;i++) mul[i]=mul[i-1]*i%mod;
inv[1]=1;
for (int i=2;i<=n;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
invmul[0]=1;
for (int i=1;i<=n;i++) invmul[i]=invmul[i-1]*inv[i]%mod;
for (int i=0;i<=n;i+=2)
g[i]=(C(i,i/2)-C(i,i/2+1)+mod)%mod;
g[0]=1;
for (int i=0;i<=n;i++) a[i]=b[i]=g[i]*invmul[i]%mod;
}
int main()
{
freopen("crazy_robot.in","r",stdin);
freopen("crazy_robot.out","w",stdout);
int fn;scanf("%d",&fn);init(fn);
int L=0;
for (n=1;n<=fn*2;n<<=1) L++;
for (int i=0;i<n;i++) r[i]=(r[i>>1]>>1)|((i&1)<<L-1);
NTT(a,1); NTT(b,1);
for (int i=0;i<=n;i++) a[i]=a[i]*b[i]%mod;
NTT(a,-1);LL inv=ksm(n,mod-2);
for (int i=0;i<=n;i++) a[i]=a[i]*inv%mod;
for (int i=0;i<=fn;i++) a[i]=a[i]*mul[i]%mod;
LL ans=0;
for (int i=0;i<=fn;i++) ans=(ans+a[i]*C(fn,i)%mod)%mod;
printf("%lld",ans);
}