luoguP5245 【模板】多项式快速幂

$B(x)=A^k(x)$

$\Rightarrow \ln B(x)=\ln A^k(x)$

$\Rightarrow \ln B(x)=k \ln A(x)$

$\Rightarrow B(x)=\exp(k \ln A(x))$

code:

#include <cmath>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <string>
#define ll long long
#define ull unsigned long long
using namespace std;
namespace IO
{
    char buf[100000],*p1,*p2;
    #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
    int rd()
    {
        int x=0; char s=nc();
        while(s<‘0‘) s=nc();
        while(s>=‘0‘) x=(((x<<2)+x)<<1)+s-‘0‘,s=nc();
        return x;
    }
    void print(int x) {if(x>=10) print(x/10);putchar(x%10+‘0‘);}
    void setIO(string s)
    {
        string in=s+".in";
        string out=s+".out";
        freopen(in.c_str(),"r",stdin);
        // freopen(out.c_str(),"w",stdout);
    }
};
const int G=3;
const int N=800005;
const int mod=998244353;
int A[N],B[N],w[2][N],mem[N*100],*ptr=mem,inv[N],tmpa[N],tmpb[N],aa[N],bb[N];
inline int qpow(int x,int y)
{
    int tmp=1;
    for(;y;y>>=1,x=(ll)x*x%mod)     if(y&1) tmp=(ll)tmp*x%mod;
    return tmp;
}
inline int INV(int a) { return qpow(a,mod-2); }
inline void ntt_init(int len)
{
    int i,j,k,mid,x,y;
    w[1][0]=w[0][0]=1,x=qpow(3,(mod-1)/len),y=qpow(x,mod-2);
    for (i=1;i<len;++i) w[0][i]=(ll)w[0][i-1]*x%mod,w[1][i]=(ll)w[1][i-1]*y%mod;
}
void NTT(int *a,int len,int flag)
{
    int i,j,k,mid,x,y;
    for(i=k=0;i<len;++i)
    {
        if(i>k)    swap(a[i],a[k]);
        for(j=len>>1;(k^=j)<j;j>>=1);
    }
    for(mid=1;mid<len;mid<<=1)
        for(i=0;i<len;i+=mid<<1)
            for(j=0;j<mid;++j)
            {
                x=a[i+j], y=(ll)w[flag==-1][len/(mid<<1)*j]*a[i+j+mid]%mod;
                a[i+j]=(x+y)%mod;
                a[i+j+mid]=(x-y+mod)%mod;
            }
    if(flag==-1)
    {
        int rev=INV(len);
        for(i=0;i<len;++i)    a[i]=(ll)a[i]*rev%mod;
    }
}
inline void getinv(int *a,int *b,int len,int la)
{
    if(len==1) { b[0]=INV(a[0]);   return; }
    getinv(a,b,len>>1,la);
    int l=len<<1,i;
    memset(A,0,l*sizeof(A[0]));
    memset(B,0,l*sizeof(A[0]));
    memcpy(A,a,min(la,len)*sizeof(a[0]));
    memcpy(B,b,len*sizeof(b[0]));
    ntt_init(l);
    NTT(A,l,1),NTT(B,l,1);
    for(i=0;i<l;++i)  A[i]=((ll)2-(ll)A[i]*B[i]%mod+mod)*B[i]%mod;
    NTT(A,l,-1);
    memcpy(b,A,len<<2);
}
void get_dao(int *a,int *b,int len)
{
    for(int i=1;i<len;++i) b[i-1]=(ll)i*a[i]%mod;
    b[len-1]=0;
}
void get_jifen(int *a,int *b,int len)
{
    for(int i=1;i<len;++i) b[i]=(ll)INV(i)*a[i-1]%mod;
    b[0]=0;
}
void get_ln(int *a,int *b,int len,int la)
{
    int l=len<<1,i;
    memset(tmpa,0,l<<2);
    memset(tmpb,0,l<<2);
    get_dao(a,tmpa,min(len,la));
    getinv(a,tmpb,len,la);
    ntt_init(l);
    NTT(tmpa,l,1),NTT(tmpb,l,1);
    for(i=0;i<l;++i) tmpa[i]=(ll)tmpa[i]*tmpb[i]%mod;
    NTT(tmpa,l,-1);
    get_jifen(tmpa,b,len);
}
void get_exp(int *a,int *b,int len,int la)
{
    if(len==1) { b[0]=1; return; }
    int l=len<<1,i;
    get_exp(a,b,len>>1,la);
    for(i=0;i<l;++i)  aa[i]=bb[i]=0;
    for(i=0;i<(len>>1);++i) aa[i]=b[i];
    get_ln(b,bb,len,len>>1);
    for(i=0;i<len;++i) bb[i]=(ll)(mod-bb[i]+(i>=la?0:a[i]))%mod;
    bb[0]=(bb[0]+1)%mod;
    ntt_init(l);
    NTT(aa,l,1),NTT(bb,l,1);
    for(i=0;i<l;++i) aa[i]=(ll)aa[i]*bb[i]%mod;
    NTT(aa,l,-1);
    for(i=0;i<len;++i)  b[i]=aa[i];
}
struct poly
{
    int len,*a;
    poly(){}
    poly(int l) {len=l,a=ptr,ptr+=l; }
    inline void rev() { reverse(a,a+len); }
    inline void fix(int l) {len=l,a=ptr,ptr+=l;}
    inline void get_mod(int l) { for(int i=l;i<len;++i) a[i]=0;  len=l;  }
    inline poly dao()
    {
        poly re(len-1);
        for(int i=1;i<len;++i)  re.a[i-1]=(ll)i*a[i]%mod;
        return re;
    }
    inline poly jifen()
    {
        poly c;
        c.fix(len+1);
        c.a[0]=0;
        for(int i=1;i<=len;++i) c.a[i]=(ll)a[i-1]*INV(i)%mod;
        return c;
    }
    inline poly Inv(int l)
    {
        poly b(l);
        getinv(a,b.a,l,len);
        return b;
    }
    inline poly ln(int l)
    {
        int lim=1;
        while(lim<=l) lim<<=1;
        poly b(lim);
        get_ln(a,b.a,lim,len);
        return b;
    }
    inline poly exp(int l)
    {
        int lim=1;
        while(lim<=l) lim<<=1;
        poly b(lim);
        get_exp(a,b.a,lim,len);
        return b;
    }
    inline poly q_pow(int k,int l)
    {
        int lim=1;
        while(lim<=l) lim<<=1;
        poly b(lim),c(lim);
        get_ln(a,b.a,lim,len);
        for(int i=0;i<b.len;++i) b.a[i]=(ll)b.a[i]*k%mod;
        get_exp(b.a,c.a,lim,b.len);
        c.get_mod(l);
        return c;
    }
    inline poly operator*(const poly &b) const
    {
        poly c(len+b.len-1);
        if(c.len<=500)
        {
            for(int i=0;i<len;++i)
                if(a[i])   for(int j=0;j<b.len;++j)  c.a[i+j]=(c.a[i+j]+(ll)(a[i])*b.a[j])%mod;
            return c;
        }
        int n=1;
        while(n<(len+b.len)) n<<=1;
        memset(A,0,n<<2);
        memset(B,0,n<<2);
        memcpy(A,a,len<<2);
        memcpy(B,b.a,b.len<<2);
        ntt_init(n);
        NTT(A,n,1), NTT(B,n,1);
        for(int i=0;i<n;++i) A[i]=(ll)A[i]*B[i]%mod;
        NTT(A,n,-1);
        memcpy(c.a,A,c.len<<2);
        return c;
    }
    poly operator+(const poly &b) const
    {
        poly c(max(len,b.len));
        for(int i=0;i<c.len;++i)  c.a[i]=((i<len?a[i]:0)+(i<b.len?b.a[i]:0))%mod;
        return c;
    }
    poly operator-(const poly &b) const
    {
        poly c(len);
        for(int i=0;i<len;++i)
        {
            if(i>=b.len)   c.a[i]=a[i];
            else c.a[i]=(a[i]-b.a[i]+mod)%mod;
        }
        return c;
    }
    poly operator/(poly u)
    {
        int n=len,m=u.len,l=1;
        while(l<(n-m+1)) l<<=1;
        rev(),u.rev();
        poly v=u.Inv(l);
        v.get_mod(n-m+1);
        poly re=(*this)*v;
        rev(),u.rev();
        re.get_mod(n-m+1);
        re.rev();
        return re;
    }
    poly operator%(poly u)
    {
        poly re=(*this)-u*(*this/u);
        re.get_mod(u.len-1);
        return re;
    }
}p[N<<2],pr;
// 插值部分
namespace Inter
{
    int xx[N],yy[N];
    #define lson now<<1
    #define rson now<<1|1
    inline void pushup(int l,int r,int now)
    {
        int mid=(l+r)>>1;
        if(r>mid)   p[now]=p[lson]*p[rson];
        else p[now]=p[lson];
    }
    void build(int l,int r,int now,int *pp)
    {
        if(l==r)
        {
            p[now].fix(2);
            p[now].a[0]=mod-pp[l];
            p[now].a[1]=1;
            return;
        }
        int mid=(l+r)>>1;
        if(l<=mid)  build(l,mid,lson,pp);
        if(r>mid)   build(mid+1,r,rson,pp);
        p[now]=p[lson]*p[rson];
    }
    // 多项式多点求值
    void get_val(int l,int r,int now,poly b,int *pp,int *t)
    {
        if(b.len<=500)
        {
            for(int i=l;i<=r;++i)
            {
                ull s=0;
                for(int j=b.len-1;j>=0;--j)
                {
                    s=((ull)s*pp[i]+b.a[j])%mod;
                    if(!(j&7))   s%=mod;
                }
                t[i]=s%mod;
            }
            return;
        }
        int mid=(l+r)>>1;
        if(l<=mid)   get_val(l,mid,lson,b%p[lson],pp,t);
        if(r>mid)    get_val(mid+1,r,rson,b%p[rson],pp,t);
    }
    // 多项式快速插值
    poly solve_polate(int l,int r,int now,int *t)
    {
        if(l==r)
        {
            poly re(1);
            re.a[0]=t[l];
            return re;
        }
        int mid=(l+r)>>1;
        poly L,R;
        L=solve_polate(l,mid,lson,t);
        R=solve_polate(mid+1,r,rson,t);
        return L*p[rson]+R*p[lson];
    }
};          

char Num[N];
int main()
{
    // IO::setIO("input");
    int i,j,n,k=0,l;
    scanf("%d%s",&n,Num),l=strlen(Num);
    poly a(n);
    for(i=0;i<l;++i) k=(ll)((ll)k*10%mod+Num[i]-‘0‘)%mod;
    for(i=0;i<n;++i) scanf("%d",&a.a[i]);
    a=a.q_pow(k,n);
    for(i=0;i<a.len;++i) printf("%d ",a.a[i]);
    return 0;
}

  

原文地址:https://www.cnblogs.com/guangheli/p/12240677.html

时间: 2024-11-08 17:03:32

luoguP5245 【模板】多项式快速幂的相关文章

luoguP5219 无聊的水题 I 多项式快速幂

有一个幼儿园容斥:最大次数恰好为 $m=$  最大次数最多为 $m$ - 最大次数最多为 $m-1$. 然后来一个多项式快速幂就好了. code: #include <cmath> #include <cstring> #include <algorithm> #include <cstdio> #include <string> #define ll long long #define ull unsigned long long using

【BZOJ3992】[SDOI2015]序列统计 NTT+多项式快速幂

[BZOJ3992][SDOI2015]序列统计 Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S. 小C用这个生成器生成了许多这样的数列.但是小C有一个问题需要你的帮助:给定整数x,求所有可以生成出的,且满足数列中所有数的乘积mod M的值等于x的不同的数列的有多少个.小C认为,两个数列{Ai}和{Bi}不同,当且仅当至少存在一个整数i,满足Ai≠Bi.另外,小C认为这个问题的答案可能

【模板】快速幂取模

快速幂取模的模板,要注意所有变量都要开成long long类型的防溢出: #include<cstdio> #include<algorithm> #include<cstring> typedef long long LL; const LL mod=1e9+7; using namespace std; LL a,b; LL mi(LL x,LL y) { LL res=1; while(y){ if(y&1) res=res*x%mod; y>>

模板——矩阵快速幂

/************************************************ Author :powatr Created Time :2015-8-5 21:06:30 File Name :b.cpp ************************************************/ #include <cstdio> #include <algorithm> #include <iostream> #include <s

【模板】快速幂

普通的快速幂,用于矩阵的版本稍后更新 1 #include<stdio.h> 2 #define lll long long 3 lll ksm(int,int); 4 int x,n; 5 int main() 6 { 7 scanf("%d%d",&x,&n); 8 printf("%lld",ksm(x,n)); 9 return 0; 10 } 11 lll ksm(int x,int n) 12 { 13 lll ret = x

[模板] 矩阵快速幂

矩阵快速幂是一个快速幂的延伸,但实际上区别不大,主要思想是一样的. 题干: 题目背景 矩阵快速幂 题目描述 给定n*n的矩阵A,求A^k 输入输出格式 输入格式: 第一行,n,k 第2至n+1行,每行n个数,第i+1行第j个数表示矩阵第i行第j列的元素 输出格式: 输出A^k 共n行,每行n个数,第i行第j个数表示矩阵第i行第j列的元素,每个元素模10^9+7 输入输出样例 输入样例#1: 复制 2 1 1 1 1 1 输出样例#1: 复制 1 1 1 1 说明 n<=100, k<=10^1

模板—十进制快速幂

用于指数爆longlong的情况,当然你也可以打高精…… 因为昨天有人提到了慢速乘,感觉挺有用的,就顺便都学了吧,而且省选也用到十进制快速幂了. #include<iostream> #include<cstring> #include<cstdio> #define LL long long using namespace std; char c[100000]; LL a,p,t; LL tenthpow(LL a) { LL ans=1,s=a; while(t&

【模板】 快速幂快速积

1 long long ksj(long long a,long long b,long long c)    //快速积取模 a*b%c  2 { 3     long long ans=0; 4     while(b){ 5         if(b&1) 6             ans=(ans+a)%c; 7         a=(a+a)%c; 8         b>>=1;  9     } 10     return ans; 11 }  12 13 long l

Luogu5245 【模板】多项式快速幂(多项式exp)

A(x)k=eklnA(x),丝毫不懂为什么指数要对p取模,只是写下exp板子. #include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 600010 #define P 9