CF755G PolandBall and Many Other Balls

CF755G PolandBall and Many Other Balls

倍增\(FFT\)

简单转移式:

\[f_{i,j}=f_{i-1,j}+f_{i-1,j-1}+f_{i-2,j-1} \]

显然跑不动。

再来一个:

\[f_{i+j,k}=\sum_t f_{i,t}f_{j,k-t}+\sum_t f_{i-1,t}f_{j-1,k-t-1} \]

上多项式!

\[F_n(x)=\sum_{i=0}^{\infty}f_{n,i}x^i \]

\[F_{i+j}(x)=F_{i}(x)F_{j}(x)+xF_{i-1}(x)F_{j-1}(x) \]

颓式子。

\[\begin{cases} F_{2n}(x)=F_{n}^2(x)+xF_{n-1}^2\\ F_{2n-1}(x)=F_{n}(x)F_{n-1}(x)+xF_{n-1}(x)F_{n-2}(x)\\ F_{2n-2}(x)=F_{n-1}^2(x)+xF_{n-2}^2(x) \end{cases} \]

因此我们可以通过\(F_{n-2},F_{n-1},F_{n}\)快速求出\(F_{2n-2},F_{2n-1},F_{2n}\)

倍增\(FFT\)即可。

\(Code:\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 131075
#define ll long long
using namespace std;
const int p=998244353;
int n,k,s,l,G[2][25],rev[N];
int f[3][N],a[N],b[N],c[N],d[N],e[N];
void Add(int &x,int y)
{
    x=(x+y)%p;
}
void Del(int &x,int y)
{
    x=(x-y+p)%p;
}
void Mul(int &x,int y)
{
    x=(ll)x*y%p;
}
int add(int x,int y)
{
    return (x+y)%p;
}
int del(int x,int y)
{
    return (x-y+p)%p;
}
int mul(int x,int y)
{
    return (ll)x*y%p;
}
int ksm(int x,int y)
{
    int ans=1;
    while (y)
    {
        if (y & 1)
            Mul(ans,x);
        Mul(x,x);
        y >>=1;
    }
    return ans;
}
void Pre()
{
    G[0][23]=ksm(3,(p-1)/(1 << 23));
    G[1][23]=ksm(G[0][23],p-2);
    for (int i=22;i;--i)
    {
        G[0][i]=mul(G[0][i+1],G[0][i+1]);
        G[1][i]=mul(G[1][i+1],G[1][i+1]);
    }
}
void NTT(int *a,int t)
{
    for (int i=0;i<s;++i)
        if (i<rev[i])
            swap(a[i],a[rev[i]]);
    for (int mid=1,o=1;mid<s;mid <<=1,++o)
        for (int j=0;j<s;j+=mid << 1)
        {
            int g=1;
            for (int k=0;k<mid;++k,Mul(g,G[t][o]))
            {
                int x=a[j+k],y=mul(g,a[j+k+mid]);
                a[j+k]=add(x,y),a[j+k+mid]=del(x,y);
            }
        }
}
void solve(int n)
{
    s=1,l=0;
    while (s<n)
        s <<=1,++l;
    for (int i=0;i<s;++i)
        rev[i]=(rev[i >> 1] >> 1) | ((i & 1) << l-1);
}
void Cut(int *a,int n,int s)
{
    memset(a+n+1,0,(s-n)*sizeof(int));
}
void shift()
{
    memcpy(a,f[0],(k+1)*sizeof(int));
    memcpy(b,f[1],(k+1)*sizeof(int));
    memcpy(c,f[2],(k+1)*sizeof(int));
    for (int i=1;i<=k;++i)
        d[i]=b[i-1],e[i]=a[i-1];
    solve((k+1) << 1);
    NTT(a,0),NTT(b,0),NTT(c,0),NTT(d,0),NTT(e,0);
    for (int i=0;i<s;++i)
        f[0][i]=add(mul(b[i],b[i]),mul(e[i],a[i])),f[1][i]=add(mul(c[i],b[i]),mul(d[i],a[i])),f[2][i]=add(mul(c[i],c[i]),mul(d[i],b[i]));
    NTT(f[0],1),NTT(f[1],1),NTT(f[2],1);
    int invs=ksm(s,p-2);
    for (int i=0;i<s;++i)
        Mul(f[0][i],invs),Mul(f[1][i],invs),Mul(f[2][i],invs);
    Cut(f[0],k,s),Cut(f[1],k,s),Cut(f[2],k,s);
    memset(a,0,s*sizeof(int)),memset(b,0,s*sizeof(int)),memset(c,0,s*sizeof(int)),memset(d,0,s*sizeof(int)),memset(e,0,s*sizeof(int));
}
void nxt()
{
    memcpy(f[0],f[1],(k+1)*sizeof(int)),memcpy(f[1],f[2],(k+1)*sizeof(int));
    for (int i=0;i<=k;++i)
        f[2][i]=add(f[1][i],(!i)?0:add(f[1][i-1],f[0][i-1]));
}
int main()
{
    Pre();
    scanf("%d%d",&n,&k);
    f[1][0]=f[2][0]=f[2][1]=1;
    s=1;
    while (s<=n)
        s <<=1,++l;
    --l;
    for (int i=l-1;i>=0;--i)
    {
        shift();
        if ((n >> i) & 1)
            nxt();
    }
    for (int i=1;i<=k;++i)
        printf("%d ",f[2][i]);
    putchar('\n');
    return 0;
}
posted @ 2020-12-28 19:23  GK0328  阅读(82)  评论(0编辑  收藏  举报