Luogu5273 【模板】多项式幂函数 (加强版)

Luogu5273 【模板】多项式幂函数 (加强版)

注意细节,首先,对于前面有\(0\)的位需要进行平移,直到出现一个非\(0\)数(特判\(0\)过多的情况)。

同时我们需要把常数项变成\(1\)才能进行\(\ln\),也就是我们需要让原多项式全体除以那个数,最后再乘回去。

对于那个数,我们进行快速幂需要用\(p-1\)(即\(\varphi(p)\)),这是费马小定理决定的;而进行多项式快速幂时只需要对\(p\)取模,这两者原理不同。

\(Code:\)

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define N 300005
#define ll long long
using namespace std;
const int p=998244353;
int n,k,k2,tn,cf=1,z0,w,s,l,G[2][35],inv[N],rev[N];
int a[N],b[N],c[N],d[N],e[N],f[N],g[N],h[N],r[N];
bool flag=false;
void ReadK(int &k,int &k2)
{
    ll s=0,s2=0;
    char c=getchar();
    while (c<'0' || c>'9')
        c=getchar();
    while ('0'<=c && c<='9')
    {
        s=(s << 3)+(s << 1)+(c^48);
        s2=(s2 << 3)+(s2 << 1)+(c^48);
        if (s>p)
            flag=true,s%=p;
        s2%=(p-1);
        c=getchar();
    }
    k=s,k2=s2;
}
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]);
    }
    inv[1]=1;
    for (int i=2;i<=300000;++i)
        inv[i]=mul(p-p/i,inv[p%i]);
}
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 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 Cut(int *a,int n,int s)
{
    memset(a+n+1,0,(s-n)*sizeof(int));
}
void GetInv(int *f,int *g,int R)
{
    if (R==2)
    {
        g[0]=ksm(f[0],p-2);
        return;
    }
    GetInv(f,g,R >> 1);
    memcpy(c,g,(R >> 2)*sizeof(int)),memcpy(d,f,(R >> 1)*sizeof(int));
    solve(R);
    NTT(c,0),NTT(d,0);
    for (int i=0;i<s;++i)
        c[i]=del(add(c[i],c[i]),mul(d[i],mul(c[i],c[i])));
    NTT(c,1);
    for (int i=0;i<s;++i)
        Mul(c[i],inv[s]);
    memcpy(g,c,(R >> 1)*sizeof(int));
    memset(c,0,s*sizeof(int)),memset(d,0,s*sizeof(int));
}
void Dev(int *a,int *b,int n)
{
    for (int i=1;i<n;++i)
        b[i-1]=mul(a[i],i);
}
void InvDev(int *a,int *b,int n)
{
    for (int i=0;i<n;++i)
        b[i+1]=mul(a[i],inv[i+1]);
}
void GetLn(int *f,int *g,int n)
{
    s=1;
    while (s<n)
        s <<=1;
    s <<=1;
    GetInv(f,a,s);
    Cut(a,n,s);
    Dev(f,b,n);
    solve(n << 1);
    NTT(a,0),NTT(b,0);
    for (int i=0;i<s;++i)
        Mul(a[i],b[i]);
    NTT(a,1);
    for (int i=0;i<s;++i)
        Mul(a[i],inv[s]);
    InvDev(a,g,n);
    Cut(g,n,s);
    memset(a,0,s*sizeof(int)),memset(b,0,s*sizeof(int));
}
void GetExp(int *f,int *g,int R)
{
    if (R==2)
    {
        g[0]=1;
        return;
    }
    GetExp(f,g,R >> 1);
    GetLn(g,h,R >> 1);
    for (int i=0;i<(R >> 1);++i)
        h[i]=del(f[i],h[i]);
    Add(h[0],1);
    memcpy(e,g,(R >> 1)*sizeof(int));
    solve(R);
    NTT(e,0),NTT(h,0);
    for (int i=0;i<s;++i)
        Mul(e[i],h[i]);
    NTT(e,1);
    for (int i=0;i<s;++i)
        Mul(e[i],inv[s]);
    memcpy(g,e,(R >> 1)*sizeof(int));
    memset(e,0,s*sizeof(int)),memset(h,0,s*sizeof(int));
}
int main()
{
    Pre();
    scanf("%d",&n),tn=n;
    ReadK(k,k2);
    for (int i=0;i<n;++i)
        scanf("%d",&r[i]);
    z0=0;
    while (z0<n && !r[z0])
        ++z0;
    if (z0 && (z0==n || flag || (ll)z0*k>n))
    {
        for (int i=0;i<n;++i)
            putchar('0'),putchar(' ');
        putchar('\n');
        return 0;
    }
    w=z0*k;
    if (z0)
    {
        for (int i=z0;i<n;++i)
            r[i-z0]=r[i];
        Cut(r,n-z0,n);
        n=n-z0;
    }
    cf=r[0];
    int iv=ksm(cf,p-2);
    for (int i=0;i<n;++i)
        Mul(r[i],iv);
    cf=ksm(cf,k2);
    GetLn(r,f,n);
    for (int i=0;i<n;++i)
        Mul(f[i],k);
    s=1;
    while (s<n)
        s <<=1;
    s <<=1;
    GetExp(f,g,s);
    for (int i=tn-1;i>=w;--i)
        g[i]=g[i-w];
    for (int i=0;i<w;++i)
        g[i]=0;
    for (int i=0;i<tn;++i)
        Mul(g[i],cf);
    for (int i=0;i<tn;++i)
        printf("%d ",add(g[i],p));
    putchar('\n');
    return 0;
}
posted @ 2021-01-01 14:14  GK0328  阅读(121)  评论(0编辑  收藏  举报