[COGS2287][HZOI2015]疯狂的机器人(NTT+Catalan数)

版权声明:口胡文章,请谨慎转载╮(╯▽╰)╭ https://blog.csdn.net/Blue_CuSO4/article/details/79978094

题目:

我是超链接

题解:

又是上下左右走的问题。。。当初我的Catalan入门就是这玩意

那么我们设g[i]表示走i步光走左右不走上下,不会不走,回到原点的方案数
可以发现当i为奇数的时候g[i]=0
考虑i为偶数的情况,肯定是选择i/2步向上走,i/2步向下走,并且时刻保证向上走的步数>=向下走的步数
这不就是Catalan数吗,可以用Cii/2Cii/21求解

显然光走上下不走左右,不会不走,回到原点的方案也是g[i]

现在我们设f[i]表示走i步,可以走上下左右,不会不走,回到原点的方案数
那么f[i]=j=0ig(j)g(ij)Cij
我们把组合数展开

f[i]=j=0ig(j)j!g(ij)(ij)!i!

卷积!又看到了熟悉的模数,NTT吧
那么如果有不走的情况呢?ans=i=0nf[i]Cni

代码:

#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);
}
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页