模板------模板

多项式算法:

  FFT:

#include<bits/stdc++.h>
using namespace std;
int read()
{
    int x=0,f=1;    char ch=getchar();
    while(ch<'0'||ch>'9')    {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')    {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;
}
const int N=3000050;
const double pi=acos(-1.0);
int n,m,limit=1,s,pos[N];
struct node
{
    double x,y;
    node (double xx=0,double yy=0)    {x=xx;y=yy;}
}a[N],b[N];
node operator + (node a,node b){return node(a.x+b.x,a.y+b.y);}
node operator - (node a,node b){return node(a.x-b.x,a.y-b.y);}
node operator * (node a,node b){return node(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
void FFT(node *nw,int opt)
{
    for(int i=0;i<limit;++i)
        if(i<pos[i])    swap(nw[i],nw[pos[i]]);
    for(int mid=1;mid<limit;mid<<=1)
    {
        node base(cos(pi/mid),opt*sin(pi/mid));
        for(int len=mid<<1,i=0;i<limit;i+=len)
        {
            node w(1,0);
            for(int j=0;j<mid;++j,w=w*base)
            {
                node x=nw[i+j];    node y=nw[i+j+mid]*w;
                nw[i+j]=x+y;    nw[i+j+mid]=x-y;
            }
        }
    }
}
int main()
{
    n=read();    m=read();
    for(int i=0;i<=n;++i)    a[i].x=read();
    for(int i=0;i<=m;++i)    b[i].x=read();
    while(limit<=n+m)    limit<<=1,s++;
    for(int i=1;i<limit;++i)    pos[i]=(pos[i>>1]>>1)|((i&1)<<(s-1));
    FFT(a,1);    FFT(b,1);
    for(int i=0;i<limit;++i)    a[i]=a[i]*b[i];
    FFT(a,-1);
    for(int i=0;i<=n+m;++i)    printf("%d ",(int)(a[i].x/limit+0.5));
    return 0;
}
View Code

  NTT:

#include<bits/stdc++.h>
#define ll long long 
using namespace std;
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9')    {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')    {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;
}
const int N=3000050;
const int p=998244353;
int n,m,limit=1,s;
int pos[N],a[N],b[N];
int ksm(int u,int v)
{
    int sum=1;
    while(v)
    {
        if(v&1)    sum=(ll)sum*u%p;
        v>>=1;    u=(ll)u*u%p;
    }
    return sum;
}
void FNT(int *nw,int opt)
{
    for(int i=0;i<limit;++i)
        if(i<pos[i])    swap(nw[i],nw[pos[i]]);
    for(int mid=1;mid<limit;mid<<=1)
    {
        int base=ksm(3,(p-1)/(mid<<1));
        if(opt==-1)    base=ksm(base,p-2);
        for(int len=mid<<1,i=0;i<limit;i+=len)
        {
            int w=1;
            for(int j=0;j<mid;++j,w=(ll)w*base%p)
            {
                int x=nw[i+j];    int y=(ll)w*nw[i+j+mid]%p;
                nw[i+j]=(x+y)%p;    nw[i+j+mid]=(x-y+p)%p;
            }
        }
    }
}
int main()
{
    n=read();    m=read();
    for(int i=0;i<=n;++i)    a[i]=read();
    for(int i=0;i<=m;++i)    b[i]=read();
    while(limit<=n+m)    limit<<=1,s++;
    for(int i=0;i<limit;++i)    pos[i]=(pos[i>>1]>>1)|((i&1)<<(s-1));
    FNT(a,1);    FNT(b,1);
    for(int i=0;i<limit;++i)    a[i]=(ll)a[i]*b[i]%p;
    FNT(a,-1);    int inv=ksm(limit,p-2);
    for(int i=0;i<=n+m;++i)    printf("%d ",(ll)a[i]*inv%p);
    return 0;
}
View Code

   FWT:

#include<bits/stdc++.h>
#define ll long long
#define p 998244353
using namespace std;
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9')    {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')    {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;
}
int n,inv;
int a[1000050],b[1000050],c[1000050];
int ksm(int u,int v)
{
    int sum=1;
    while(v)
    {
        if(v&1)    sum=(ll)sum*u%p;
        v>>=1;    u=(ll)u*u%p;
    }
    return sum;
}
void FWTOR(int *nw,int opt)
{
    for(int mid=1;mid<n;mid<<=1)
        for(int len=mid<<1,i=0;i<n;i+=len)
            for(int j=0;j<mid;++j)
                if(opt==1)    nw[i+j+mid]=(nw[i+j]+nw[i+j+mid])%p;
                else    nw[i+j+mid]=(nw[i+j+mid]-nw[i+j]+p)%p;
}
void FWTAND(int *nw,int opt)
{
    for(int mid=1;mid<n;mid<<=1)
        for(int len=mid<<1,i=0;i<n;i+=len)
            for(int j=0;j<mid;++j)
                if(opt==1)    nw[i+j]=(nw[i+j]+nw[i+j+mid])%p;
                else    nw[i+j]=(nw[i+j]-nw[i+j+mid]+p)%p;
}
void FWTXOR(int *nw,int opt)
{
    for(int mid=1;mid<n;mid<<=1)
        for(int len=mid<<1,i=0;i<n;i+=len)
            for(int j=0;j<mid;++j)
            {
                int x=nw[i+j];    int y=nw[i+j+mid];
                if(opt==1)    nw[i+j]=(x+y)%p,nw[i+j+mid]=(x-y+p)%p;
                else    nw[i+j]=(ll)(x+y)*inv%p,nw[i+j+mid]=(ll)(x-y+p)*inv%p;
                    
            }
}
int main()
{
    n=1<<read();    inv=ksm(2,p-2);
    for(int i=0;i<n;++i)    a[i]=read();
    for(int i=0;i<n;++i)    b[i]=read();
    FWTOR(a,1);        FWTOR(b,1);
    for(int i=0;i<n;++i)    c[i]=(ll)a[i]*b[i]%p;
    FWTOR(a,-1);    FWTOR(b,-1);    FWTOR(c,-1);
    for(int i=0;i<n;++i)    printf("%d ",c[i]);    puts(" ");
    FWTAND(a,1);    FWTAND(b,1);
    for(int i=0;i<n;++i)    c[i]=(ll)a[i]*b[i]%p;
    FWTAND(a,-1);    FWTAND(b,-1);    FWTAND(c,-1);
    for(int i=0;i<n;++i)    printf("%d ",c[i]);    puts(" ");
    FWTXOR(a,1);    FWTXOR(b,1);
    for(int i=0;i<n;++i)    c[i]=(ll)a[i]*b[i]%p;
    FWTXOR(a,-1);FWTXOR(b,-1);    FWTXOR(c,-1);
    for(int i=0;i<n;++i)    printf("%d ",c[i]);    puts(" ");
    return 0;
}
View Code

  多项式求逆:

#include<bits/stdc++.h>
#define ll long long
#define p 998244353
using namespace std;
int read()
{
    int x=0,f=1;    char ch=getchar();
    while(ch<'0'||ch>'9')    {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')    {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*f;
}
const int N=400050;
int n,len,limit,s;
int f[N],g[N],a[N],b[N];
int pos[N];
int ksm(int u,int v)
{
    int sum=1;
    while(v)
    {
        if(v&1)    sum=(ll)sum*u%p;
        v>>=1;    u=(ll)u*u%p;
    }
    return sum;
}
void NTT(int *nw,int opt)
{
    for(int i=0;i<limit;++i)
        if(i<pos[i])    swap(nw[i],nw[pos[i]]);
    for(int mid=1;mid<limit;mid<<=1)
    {
        int base=ksm(3,(p-1)/(mid<<1));
        if(opt==-1)    base=ksm(base,p-2);
        for(int len=mid<<1,i=0;i<limit;i+=len)
        {
            int w=1;
            for(int j=0;j<mid;++j,w=(ll)w*base%p)
            {
                int x=nw[i+j];    int y=(ll)w*nw[i+j+mid]%p;
                nw[i+j]=(x+y)%p;    nw[i+j+mid]=(x-y+p)%p;
            }
        }
    }
}
int main()
{
    n=read()-1;
    for(int i=0;i<=n;++i)    f[i]=read();
    limit=2;    len=1;    s=1;    g[0]=ksm(f[0],p-2);
    while(len<=n)
    {
        limit<<=1;    len<<=1;    s++;
        for(int i=0;i<limit;++i)    pos[i]=(pos[i>>1]>>1)|((i&1)<<(s-1));
        for(int i=0;i<len;++i)    a[i]=f[i],b[i]=g[i];
        NTT(a,1);    NTT(b,1);
        for(int i=0;i<limit;++i)    a[i]=((ll)2*b[i]%p-(ll)a[i]*b[i]%p*b[i]%p+p)%p;
        NTT(a,-1);    int inv=ksm(limit,p-2);
        for(int i=0;i<len;++i)    g[i]=(ll)a[i]*inv%p;
    }
    for(int i=0;i<=n;++i)    printf("%d ",g[i]);
    return 0;
}
View Code

  多项式开根(求逆,开根):

#include<bits/stdc++.h>
#define ll long long
#define p 998244353
using namespace std;
int read()
{
    int x=0,f=1;    char ch=getchar();
    while(ch<'0'||ch>'9')    {if(ch=='-')    f=-1;    ch=getchar();}
    while(ch>='0'&&ch<='9')    {x=(x<<3)+(x<<1)+(ch^48);    ch=getchar();}
    return x*f;
}
int n,m,inv2;
int limit,s,pos[400050];
int f[400050],g[400050],h[400050];
int a_[400050],b_[400050],c_[400050];
int a__[400050],b__[400050],c__[400050],d__[400050];
int ksm(int u,int v)
{
    int sum=1;
    while(v)
    {
        if(v&1)    sum=(ll)sum*u%p;
        v>>=1;    u=(ll)u*u%p;
    }
    return sum;
}
void fir(int len)
{
    limit=1;    s=0;
    while(limit<=len+len)    limit<<=1,s++;
    for(int i=0;i<limit;++i)    pos[i]=(pos[i>>1]>>1)|((i&1)<<(s-1));
}
void NTT(int *nw,int opt)
{
    for(int i=0;i<limit;++i)
        if(i<pos[i])    swap(nw[i],nw[pos[i]]);
    for(int mid=1;mid<limit;mid<<=1)
    {
        int base=ksm(3,(p-1)/(mid<<1));
        if(opt==-1)    base=ksm(base,p-2);
        for(int len=mid<<1,i=0;i<limit;i+=len)
        {
            int w=1;
            for(int j=0;j<mid;++j,w=(ll)w*base%p)
            {
                int x=nw[i+j];    int y=(ll)w*nw[i+j+mid]%p;
                nw[i+j]=(x+y)%p;    nw[i+j+mid]=(x-y+p)%p;
            }
        }
    }
}
void INV(int *A,int *B,int N)
{
    int len=1;    B[0]=ksm(A[0],p-2);
    while(len<=N)
    {
        len<<=1;    fir(len-1);
        for(int i=0;i<limit;++i)    a_[i]=b_[i]=0;
        for(int i=0;i<len;++i)    a_[i]=A[i],b_[i]=B[i];
        NTT(a_,1);    NTT(b_,1);
        for(int i=0;i<limit;++i)    c_[i]=((ll)2*b_[i]%p-(ll)a_[i]*b_[i]%p*b_[i]%p+p)%p;
        NTT(c_,-1);    int inv=ksm(limit,p-2);
        for(int i=0;i<len;++i)    B[i]=(ll)c_[i]*inv%p;
    }
}
void SQRT(int *A,int *B,int N)
{
    int len=1;    B[0]=1;
    while(len<=N)
    {
        len<<=1;    fir(len-1);
        for(int i=0;i<limit;++i)    a__[i]=b__[i]=c__[i]=0;
        for(int i=0;i<len;++i)    a__[i]=A[i],b__[i]=B[i];
        INV(b__,c__,len-1);    NTT(a__,1);    NTT(b__,1);    NTT(c__,1);
        for(int i=0;i<limit;++i)        d__[i]=(ll)((ll)a__[i]+(ll)b__[i]*b__[i]%p)%p*inv2%p*c__[i]%p;
        NTT(d__,-1);    int inv=ksm(limit,p-2);
        for(int i=0;i<len;++i)    B[i]=(ll)d__[i]*inv%p;
    }
}
int main()
{
    n=read()-1;    inv2=ksm(2,p-2);
    for(int i=0;i<=n;++i)    f[i]=read();    
    SQRT(f,g,n);
    for(int i=0;i<=n;++i)    printf("%d ",g[i]);
    return 0;
}
View Code

  多项式除法(求逆,除法,取模):

#include<bits/stdc++.h>
#define ll long long
#define p 998244353
using namespace std;
int read()
{
    int x=0,f=1;    char ch=getchar();
    while(ch<'0'||ch>'9')    {if(ch=='-')    f=-1;    ch=getchar();}
    while(ch>='0'&&ch<='9')    {x=(x<<3)+(x<<1)+(ch^48);    ch=getchar();}
    return x*f;
}
const int N=2000050;
int n,m,nm;
int limit,s,pos[N];
int f[N],g[N],h[N];
int val[N],ans[N];
int a[N],b[N],c[N];
int _a[N],_b[N],_c[N];
int __a[N],__b[N],__c[N],__d[N];
void fir(int len)
{
    limit=1;s=0;
    while(limit<=len)    limit<<=1,s++;
    for(int i=0;i<limit;++i)    pos[i]=(pos[i>>1]>>1)|((i&1)<<(s-1));
}
int ksm(int u,int v)
{
    int sum=1;
    while(v)
    {
        if(v&1)    sum=(ll)sum*u%p;
        v>>=1;    u=(ll)u*u%p;
    }
    return sum;
}
void NTT(int *nw,int opt)
{
    for(int i=0;i<limit;++i)
        if(i<pos[i])    swap(nw[i],nw[pos[i]]);
    for(int mid=1;mid<limit;mid<<=1)
    {
        int base=ksm(3,(p-1)/(mid<<1));
        if(opt==-1)    base=ksm(base,p-2);
        for(int len=mid<<1,i=0;i<limit;i+=len)
        {
            int w=1;
            for(int j=0;j<mid;j++,w=(ll)w*base%p)
            {
                int x=nw[i+j];    int y=(ll)w*nw[i+j+mid]%p;
                nw[i+j]=(x+y)%p;    nw[i+j+mid]=(x-y+p)%p;
            }
        }
    }
}
void MUL(int *A,int *B,int *C,int N,int M)
{
    fir(N+M);
    for(int i=0;i<limit;++i)    a[i]=b[i]=0;
    for(int i=0;i<=N;++i)    a[i]=A[i];
    for(int i=0;i<=M;++i)    b[i]=B[i];
    NTT(a,1);    NTT(b,1);
    for(int i=0;i<limit;++i)    c[i]=(ll)a[i]*b[i]%p;
    NTT(c,-1);    int inv=ksm(limit,p-2);
    for(int i=0;i<=N+M;++i)        C[i]=(ll)c[i]*inv%p;
}
void INV(int *A,int *B,int N)
{
    int len=1;    _c[0]=ksm(A[0],p-2);    _c[1]=0;
    while(len<=N)
    {
        len<<=1;    fir(len+len-1);
        for(int i=0;i<limit;++i)    _a[i]=_b[i]=0;
        for(int i=0;i<len;++i)    _a[i]=A[i],_b[i]=_c[i];
        NTT(_a,1);    NTT(_b,1);
        for(int i=0;i<limit;++i)    _c[i]=((ll)_b[i]*2-(ll)_a[i]*_b[i]%p*_b[i]%p+p)%p;
        NTT(_c,-1);    int inv=ksm(limit,p-2);
        for(int i=0;i<len;++i)    _c[i]=(ll)_c[i]*inv%p;
        for(int i=len;i<limit;++i)    _c[i]=0;
    }
    for(int i=0;i<=N;++i)    B[i]=_c[i];
}
void MOD(int *A,int *B,int *C,int N,int M)
{
    fir(N+N);
    for(int i=0;i<limit;++i)    __a[i]=__b[i]=0;
    for(int i=0;i<=N;++i)    __a[i]=A[N-i];
    for(int i=0;i<=M;++i)    __b[i]=B[M-i];
    INV(__b,__b,N-M);    MUL(__a,__b,__c,N,N-M);    reverse(__c,__c+N-M+1);
    for(int i=0;i<=N;++i)    __a[i]=A[i];
    for(int i=0;i<=M;++i)    __b[i]=B[i];
    for(int i=0;i<=N-M;++i)    cout<<__c[i]<<" ";    cout<<endl;
    MUL(__b,__c,__d,M,N-M);
    for(int i=0;i<M;++i)    C[i]=(__a[i]-__d[i]+p)%p;
    for(int i=0;i<M;++i)    cout<<C[i]<<" ";
}
int main()
{
    n=read();    m=read();
    for(int i=0;i<=n;++i)    f[i]=read();
    for(int i=0;i<=m;++i)    g[i]=read();
    MOD(f,g,h,n,m);
    return 0;
}
View Code

  多项式快速幂(对数,指数):

#include<bits/stdc++.h>
#define ll long long
#define p 998244353
using namespace std;
const int N=400050;
int read()
{
    ll x=0,f=1;    char ch=getchar();
    while(ch<'0'||ch>'9')    {if(ch=='-')    f=-1;    ch=getchar();}
    while(ch>='0'&&ch<='9')    {x=((x<<3)+(x<<1)+(ch^48))%p;    ch=getchar();};
    return (int)x*f;
}
int n,m,inv2;
int limit,s,pos[N];
int f[N],g[N],h[N];
int a[N],b[N],c[N];
int _a[N],_b[N],_c[N],_ans[N];
int __a[N],__b[N],__c[N];
int ___a[N],___b[N],___c[N],___d[N],___ans[N];
int ksm(int u,int v)
{
    int sum=1;
    while(v)
    {
        if(v&1)    sum=(ll)sum*u%p;
        v>>=1;    u=(ll)u*u%p;
    }
    return sum;
}
void fir(int len)
{
    limit=1;    s=0;
    while(limit<=len)    limit<<=1,s++;
    for(int i=0;i<limit;++i)    pos[i]=(pos[i>>1]>>1)|((i&1)<<(s-1));
}
void NTT(int *nw,int opt)
{
    for(int i=0;i<limit;++i)
        if(i<pos[i])    swap(nw[i],nw[pos[i]]);
    for(int mid=1;mid<limit;mid<<=1)
    {
        int base=ksm(3,(p-1)/(mid<<1));
        if(opt==-1)    base=ksm(base,p-2);
        for(int len=mid<<1,i=0;i<limit;i+=len)
        {
            int w=1;
            for(int j=0;j<mid;++j,w=(ll)w*base%p)
            {
                int x=nw[i+j];    int y=(ll)w*nw[i+j+mid]%p;
                nw[i+j]=(x+y)%p;    nw[i+j+mid]=(x-y+p)%p;
            }
        }
    }
}
void DIREV(int *A,int *B,int N)
{
    for(int i=0;i<N;++i)
        B[i]=(ll)A[i+1]*(i+1)%p;
    B[n]=0;
}
void INTER(int *A,int *B,int N)
{
    for(int i=N;i>=1;--i)
        B[i]=(ll)A[i-1]*ksm(i,p-2)%p;
    B[0]=0;
}
void MUL(int *A,int *B,int *C,int N)
{
    fir(N+N);
    for(int i=0;i<limit;++i)    a[i]=b[i]=0;
    for(int i=0;i<=N;++i)    a[i]=A[i],b[i]=B[i];
    NTT(a,1);    NTT(b,1);
    for(int i=0;i<limit;++i)    c[i]=(ll)a[i]*b[i]%p;
    NTT(c,-1);    int inv=ksm(limit,p-2);
    for(int i=0;i<=N+N;++i)        C[i]=(ll)c[i]*inv%p;
}
void INV(int *A,int *B,int N)
{
    int len=1;    _ans[0]=ksm(A[0],p-2);    _ans[1]=0;
    while(len<=N)
    {
        len<<=1;    fir(len+len-1);
        for(int i=0;i<limit;++i)    _a[i]=_b[i]=0;
        for(int i=0;i<len;++i)    _a[i]=A[i],_b[i]=_ans[i];
        NTT(_a,1);    NTT(_b,1);
        for(int i=0;i<limit;++i)    _c[i]=((ll)2*_b[i]%p-(ll)_a[i]*_b[i]%p*_b[i]%p+p)%p;
        NTT(_c,-1);    int inv=ksm(limit,p-2);
        for(int i=0;i<len;++i)    _ans[i]=(ll)_c[i]*inv%p;
        for(int i=len;i<limit;++i)    _ans[i]=0;
    }
    for(int i=0;i<=N;++i)    B[i]=_ans[i];
}
void LN(int *A,int *B,int N)
{
    for(int i=0;i<=N;++i)    __a[i]=A[i];
    INV(__a,__b,N);    DIREV(__a,__c,N);
    MUL(__b,__c,__a,N);    INTER(__a,__a,N);
    for(int i=0;i<=N;++i)    B[i]=__a[i];
}
void EXP(int *A,int *B,int N)
{
    int len=1;    ___ans[0]=1;    ___ans[1]=0;
    while(len<=N)
    {
        len<<=1;
        LN(___ans,___a,len-1);    ___a[0]=(___a[0]-1+p)%p;
        for(int i=0;i<len;++i)    ___a[i]=(p-___a[i]+A[i])%p;
        MUL(___ans,___a,___ans,len-1);
        for(int i=len;i<limit;++i)    ___ans[i]=0;
    }
    for(int i=0;i<=N;++i)    B[i]=___ans[i];
}
int main()
{
    n=read()-1;    m=read();
    for(int i=0;i<=n;++i)    f[i]=read();
    LN(f,f,n);
    for(int i=0;i<=n;++i)    f[i]=(ll)m*f[i]%p;
    EXP(f,f,n);
    for(int i=0;i<=n;++i)    printf("%d ",f[i]);
    return 0;
}
View Code

  多项式多点求值:

#include<bits/stdc++.h>
#define ll long long
#define p 998244353
using namespace std;
int read()
{
    int x=0,f=1;    char ch=getchar();
    while(ch<'0'||ch>'9')    {if(ch=='-')    f=-1;    ch=getchar();}
    while(ch>='0'&&ch<='9')    {x=(x<<3)+(x<<1)+(ch^48);    ch=getchar();}
    return x*f;
}
const int N=4000050;
int n,m,LIMIT,S,SUM;
int limit,s,pos[N];
int val[N],ans[N];
int aa[N],ab[N],ac[N];
int ba[N],bb[N],bc[N];
int ca[N],cb[N],cc[N],cd[N];
int t[16][N],f[N],g[N],h[N],r[N];
int w[N],iw[N],inv[N];
int add(int x,int y){    return x+y>p? x+y-p:x+y;}
int mul(int x,int y){    return (ll)x*y-(ll)x*y/p*p;}
void fir(int len)
{
    limit=1;    s=0;
    while(limit<=len)    limit<<=1,s++;
    for(int i=0;i<limit;++i)    pos[i]=(pos[i>>1]>>1)|((i&1)<<(s-1));
}
int ksm(int u,int v)
{
    int sum=1;
    while(v)
    {
        if(v&1)    sum=mul(sum,u);
        v>>=1;    u=mul(u,u);
    }
    return sum;
}
void NTT(int *nw,int *W)
{
    for(int i=0;i<limit;++i)
        if(i<pos[i])    swap(nw[i],nw[pos[i]]);
    for(int mid=1;mid<limit;mid<<=1)
    {
        int base=LIMIT/mid;
        for(int len=mid<<1,i=0;i<limit;i+=len)
        {
            int k=0;
            for(int j=0;j<mid;j++,k+=base)
            {
                int x=nw[i+j];    int y=mul(W[k],nw[i+j+mid]);
                nw[i+j]=add(x,y);    nw[i+j+mid]=add(x,p-y);
            }
        }
    }
}
void MUL(int *A,int *B,int *C,int N,int M,int *a=aa,int *b=ab,int *c=ac)
{
    fir(N+M);
    for(int i=0;i<limit;++i)    a[i]=b[i]=0;
    for(int i=0;i<=N;++i)    a[i]=A[i];
    for(int i=0;i<=M;++i)    b[i]=B[i];
    NTT(a,w);    NTT(b,w);
    for(int i=0;i<limit;++i)    c[i]=mul(a[i],b[i]);
    NTT(c,iw);
    for(int i=0;i<=N+M;++i)        C[i]=mul(c[i],inv[s]);
}
void INV(int *A,int *B,int N,int *a=ba,int *b=bb,int *c=bc)
{
    int len=1;    c[0]=ksm(A[0],p-2);    c[1]=0;
    while(len<=N)
    {
        len<<=1;    fir(len);
        for(int i=0;i<limit;++i)    a[i]=b[i]=0;
        for(int i=0;i<len;++i)    a[i]=A[i],b[i]=c[i];
        NTT(a,w);    NTT(b,w);
        for(int i=0;i<limit;++i)    c[i]=add(mul(b[i],2),p-mul(a[i],mul(b[i],b[i])));
        NTT(c,iw);
        for(int i=0;i<len;++i)    c[i]=mul(c[i],inv[s]);;
        for(int i=len;i<limit;++i)    c[i]=0;
    }
    for(int i=0;i<=N;++i)    B[i]=c[i];
}
void MOD(int *A,int *B,int *C,int N,int M,int *a=ca,int *b=cb,int *c=cc,int *d=cd)
{
    fir(N+N);
    for(int i=0;i<limit;++i)    a[i]=b[i]=0;
    for(int i=0;i<=N;++i)    a[i]=A[N-i];
    for(int i=0;i<=M;++i)    b[i]=B[M-i];
    INV(b,b,N-M);    MUL(a,b,c,N,N-M);    reverse(c,c+N-M+1);
    for(int i=0;i<=N;++i)    a[i]=A[i];
    for(int i=0;i<=M;++i)    b[i]=B[i];
    MUL(b,c,d,M,N-M);
    for(int i=0;i<M;++i)    C[i]=add(a[i],p-d[i]);
}
void calc()
{
    w[0]=iw[0]=1;    fir(n+n);    LIMIT=limit>>1;    S=s-1;
    for(int i=1;i<limit;++i)    w[i]=ksm(3,(p-1)/limit*i);
    for(int i=1;i<limit;++i)    iw[i]=ksm(w[i],p-2);
    for(int i=0;i<=s;++i)    inv[i]=ksm(1<<i,p-2);
    for(int i=0;i<LIMIT;++i)    t[0][i]=p-1;
    for(int mid=1,lg=0;mid<LIMIT/2;mid<<=1,lg++)
    {
        for(int len=mid<<1,i=0;i<LIMIT;i+=len)
        {
            f[0]=g[0]=1;
            for(int j=0;j<mid;++j)    f[j+1]=t[lg][i+j];
            for(int j=0;j<mid;++j)    g[j+1]=t[lg][i+j+mid];
            for(int j=0;j<mid;++j)    f[0]=mul(f[0],val[i+j]);
            for(int j=0;j<mid;++j)    g[0]=mul(g[0],val[i+j+mid]);
            MUL(f,g,h,mid,mid);
            for(int j=0;j<len;++j)    t[lg+1][i+j]=h[j+1];
        }
    }
}
void solve()
{
    for(int mid=LIMIT/2,lg=S-1;mid>=1;mid>>=1,lg--)
        for(int len=mid<<1,i=0;i<LIMIT;i+=len)
        {
            f[0]=g[0]=1;
            for(int j=0;j<len;++j)    h[j]=ans[i+j];
            for(int j=0;j<mid;++j)    f[j+1]=t[lg][i+j];
            for(int j=0;j<mid;++j)    g[j+1]=t[lg][i+j+mid];
            for(int j=0;j<mid;++j)    f[0]=mul(f[0],val[i+j]);
            for(int j=0;j<mid;++j)    g[0]=mul(g[0],val[i+j+mid]);
            MOD(h,f,r,len-1,mid);
            for(int j=0;j<mid;++j)    ans[i+j]=r[j];
            MOD(h,g,r,len-1,mid);
             for(int j=0;j<mid;++j)    ans[i+j+mid]=r[j];
        }
}
int main()
{
    n=read();    m=read();
    for(int i=0;i<=n;++i)    ans[i]=read();
    for(int i=1;i<=m;++i)    val[i]=read();
    calc();    solve();
    for(int i=1;i<=m;++i)    printf("%d\n",ans[i]);
    return 0;
}
View Code

字符串算法:

   后缀数组:

#include<bits/stdc++.h>
using namespace std;
int n,m;
char s[1000050];
int height[2000050];
int sa[2000050],sb[2000050];
int rk[2000050],t[2000050],tot,top;
void qsort()
{
    for(int i=0;i<=m;i++)    t[i]=0;
    for(int i=1;i<=n;i++)    t[rk[i]]++;
    for(int i=1;i<=m;++i)    t[i]+=t[i-1];
    for(int i=n;i>=1;--i)    sa[t[rk[sb[i]]]--]=sb[i];
}
void calc_sa()
{
    for(int i=1;i<=n;++i)    sb[i]=i;
    for(int i=1;i<=n;++i)    rk[i]=s[i];
    for(int i=1;i<=n;++i)    m=max(m,rk[i]);
    qsort();
    for(int k=1;tot<n;k<<=1)
    {
        tot=top=0;
        for(int i=1;i<=k;++i)    sb[++top]=n-k+i;
        for(int i=1;i<=n;++i)    if(sa[i]>k)    sb[++top]=sa[i]-k;
        qsort();    swap(rk,sb);    rk[sa[1]]=++tot;
        for(int i=2;i<=n;++i)
        {
            if(sb[sa[i]]!=sb[sa[i-1]]||sb[sa[i]+k]!=sb[sa[i-1]+k])    ++tot;
            rk[sa[i]]=tot;
        }
        m=tot;
    }
}
void calc_height()
{
    for(int i=1,j,k=0;i<=n;++i)
    {
        j=sa[rk[i]-1];    if(k)    --k;
        while(s[i+k]==s[j+k])    ++k;
        height[rk[i]]=k;
    }
}
int main()
{
    scanf("%s",s+1);    n=strlen(s+1);    calc_sa();    calc_height();
    for(int i=1;i<=n;++i)    printf("%d ",sa[i]);    puts(" ");
    for(int i=1;i<=n;++i)    printf("%d ",height[i]);
    return 0;
}
View Code

 数论:

  第一类斯特林数(行):

#include<bits/stdc++.h>
#define ll long long
#define p 167772161
using namespace std;
int n,limit,s;
int fac[1000050];
int fav[1000050];
int tmp[1000050];
int pos[1000050];
int ans[1000050];
int a[1000050];
int b[1000050];
int c[1000050];
int ksm(int u,int v)
{
    int sum=1;
    while(v)
    {
        if(v&1)    sum=(ll)sum*u%p;
        v>>=1;    u=(ll)u*u%p;
    }
    return sum;
}
void fir(int len)
{
    limit=1;    s=0;
    while(limit<=(len<<1))    limit<<=1,s++;
    for(int i=0;i<limit;++i)    pos[i]=(pos[i>>1]>>1)|((i&1)<<(s-1));
}
void NTT(int *nw,int opt)
{
    for(int i=0;i<limit;++i)
        if(i<pos[i])    swap(nw[i],nw[pos[i]]);
    for(int mid=1;mid<limit;mid<<=1)
    {
        int base=ksm(3,(p-1)/(mid<<1));
        if(opt==-1)    base=ksm(base,p-2);
        for(int len=mid<<1,i=0;i<limit;i+=len)
        {
            int w=1;
            for(int j=0;j<mid;j++,w=(ll)w*base%p)
            {
                int x=nw[i+j];    int y=(ll)w*nw[i+j+mid]%p;
                nw[i+j]=(x+y)%p;    nw[i+j+mid]=(x-y+p)%p;
            }
        }
    }
}
void mul(int *A,int *B,int *C,int len)
{
    for(int i=len+1;i<limit;++i)    A[i]=B[i]=0;
    NTT(A,1);    NTT(B,1);
    for(int i=0;i<limit;++i)    C[i]=(ll)A[i]*B[i]%p;
    NTT(C,-1);    int INV=ksm(limit,p-2);
    for(int i=0;i<limit;++i)    C[i]=(ll)C[i]*INV%p;
}
void solve(int LEN)
{
    if(LEN<=1)    {    ans[LEN]=1;    return ;}
    solve(LEN>>1);    int len=LEN>>1;    fir(len);
    for(int i=1;i<=len;++i)    tmp[i]=(ll)tmp[i-1]*len%p;
    for(int i=0;i<=len;++i)    a[i]=(ll)tmp[i]*fav[i]%p;
    for(int i=0;i<=len;++i)    b[i]=(ll)ans[i]*fac[i]%p;
    for(int i=0;i<=(len>>1);++i)    swap(b[i],b[len-i]);
    mul(a,b,c,len);
    for(int i=0;i<=len;++i)    a[i]=(ll)c[len-i]*fav[i]%p;
    for(int i=0;i<=len;++i)    b[i]=ans[i];
    mul(a,b,c,len);
    for(int i=0;i<=LEN;++i)    ans[i]=c[i];
    if(LEN&1)
        for(int i=1;i<=LEN;++i)
            ans[i]=((ll)c[i]*(LEN-1)%p+c[i-1])%p;
}
int main()
{
    scanf("%d",&n);
    fac[0]=fac[1]=fav[0]=fav[1]=tmp[0]=1;
    for(int i=1;i<=n;++i)    fac[i]=(ll)fac[i-1]*i%p;
    for(int i=2;i<=n;++i)    fav[i]=p-(ll)p/i*fav[p%i]%p;
    for(int i=1;i<=n;++i)    fav[i]=(ll)fav[i-1]*fav[i]%p;
    solve(n);
    for(int i=0;i<=n;++i)    printf("%d ",ans[i]);
    return 0;
}
View Code

    第二类斯特林数(行):

#include<bits/stdc++.h>
#define ll long long
#define p 167772161
using namespace std;
int n,limit,s;
int fac[1000050];
int fav[1000050];
int pos[1000050];
int ans[1000050];
int a[1000050];
int b[1000050];
int ksm(int u,int v)
{
    int sum=1;
    while(v)
    {
        if(v&1)    sum=(ll)sum*u%p;
        v>>=1;    u=(ll)u*u%p;
    }
    return sum;
}
void calc(int len)
{
    limit=1;    s=0;
    while(limit<=(len<<1))    limit<<=1,s++;
    for(int i=0;i<limit;++i)    pos[i]=(pos[i>>1]>>1)|((i&1)<<(s-1));
}
void NTT(int *nw,int opt)
{
    for(int i=0;i<limit;++i)
        if(i<pos[i])    swap(nw[i],nw[pos[i]]);
    for(int mid=1;mid<limit;mid<<=1)
    {
        int base=ksm(3,(p-1)/(mid<<1));
        if(opt==-1)    base=ksm(base,p-2);
        for(int len=mid<<1,i=0;i<limit;i+=len)
        {
            int w=1;
            for(int j=0;j<mid;j++,w=(ll)w*base%p)
            {
                int x=nw[i+j];    int y=(ll)w*nw[i+j+mid]%p;
                nw[i+j]=(x+y)%p;    nw[i+j+mid]=(x-y+p)%p;
            }
        }
    }
}
void mul(int *A,int *B,int *C,int len)
{
    for(int i=len+1;i<limit;++i)    A[i]=B[i]=0;
    NTT(A,1);    NTT(B,1);
    for(int i=0;i<limit;++i)    C[i]=(ll)A[i]*B[i]%p;
    NTT(C,-1);    int INV=ksm(limit,p-2);
    for(int i=0;i<limit;++i)    C[i]=(ll)C[i]*INV%p;
}
int main()
{
    scanf("%d",&n);
    fac[0]=fac[1]=fav[0]=fav[1]=1;
    for(int i=1;i<=n;++i)    fac[i]=(ll)fac[i-1]*i%p;
    for(int i=2;i<=n;++i)    fav[i]=p-(ll)p/i*fav[p%i]%p;
    for(int i=1;i<=n;++i)    fav[i]=(ll)fav[i-1]*fav[i]%p;
    for(int i=0;i<=n;++i)    a[i]=(i&1)?    -fav[i]:fav[i];
    for(int i=0;i<=n;++i)    b[i]=(ll)ksm(i,n)*fav[i]%p;
    calc(n);    mul(a,b,ans,n);
    for(int i=0;i<=n;++i)    printf("%d ",ans[i]);
    return 0;
}
View Code

 网络流:

  求解一组最小割边:

#include<bits/stdc++.h>
#define INF 1<<30
using namespace std;
int read()
{
    int x=0,f=1;    char ch=getchar();
    while(ch<'0'||ch>'9')    {if(ch=='-')    f=-1;    ch=getchar();}
    while(ch>='0'&&ch<='9')    {x=(x<<3)+(x<<1)+(ch^48);    ch=getchar();}
    return x*f;
}
queue<int >q;
int dis[100050];
bool vis[100050]; 
int n,m,s,t,tot=1,x,y,z,ans;
int head[100050],nex[100050],ver[100050],flow[100050];
void add(int x,int y,int z)
{
    ++tot;nex[tot]=head[x];head[x]=tot;ver[tot]=y;flow[tot]=z;
    ++tot;nex[tot]=head[y];head[y]=tot;ver[tot]=x;flow[tot]=0;
}
bool bfs()
{
    memset(dis,0,sizeof(dis));
    q.push(s);    dis[s]=1;
    while(!q.empty())
    {
        int u=q.front();    q.pop();
        for(int i=head[u];i;i=nex[i])
        {
            int v=ver[i];
            if(!dis[v]&&flow[i])
            {
                dis[v]=dis[u]+1;
                if(v!=t)    q.push(v);
            }
        }
    }
    return dis[t];
}
int dfs(int u,int FLOW)
{
    if(u==t)    return FLOW;
    int VAL=0;
    for(int i=head[u];i;i=nex[i])
    {
        int v=ver[i];
        if(dis[v]==dis[u]+1&&flow[i])
        {
            int tmp=dfs(v,min(FLOW,flow[i]));
            flow[i]-=tmp;    flow[i^1]+=tmp;
            VAL+=tmp;    FLOW-=tmp;
            if(!tmp)    dis[v]=0;
            if(!FLOW)    break;
        }
    }
    return VAL;
}
void calc()
{
    q.push(s);    vis[s]=true;
    while(!q.empty())
    {
        int u=q.front();    q.pop();
        for(int i=head[u];i;i=nex[i])
        {
            int v=ver[i];
            if(!flow[i])    continue;
            if(!vis[v])
            {
                q.push(v);
                vis[v]=true;
            }
        }
    }
}
int main()
{
    n=read();    m=read();    s=read();    t=read()+n;
    for(int i=1;i<=n;++i)    add(i,i+n,read());
    for(int i=1;i<=m;++i)
    {
        x=read();    y=read();
        add(x+n,y,INF);    add(y+n,x,INF);
    }
    while(bfs())    ans+=dfs(s,INF);
    calc();
    for(int i=1;i<=n;++i)
        if(vis[i]&&!vis[i+n])    printf("%d ",i);
    return 0;
}
View Code

    求解可行边与必须边:

#include<bits/stdc++.h>
using namespace std;
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9')    {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')    x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    return x*f;
}
int n,m,x,y,z,S,T;
int dfn[10050],low[10050],t[10050],top,cnt,col[10050],sum;
int head[10050],nex[120050],ver[120050],flow[120050],tot=1;
int dis[10050]; queue<int >q;
bool bfs()
{
    memset(dis,0,sizeof(dis));
    q.push(S);    dis[S]=1;
    while(!q.empty())
    {
        int u=q.front();    q.pop();
        for(int i=head[u];i;i=nex[i])
        {
            int v=ver[i];
            if(!dis[v]&&flow[i])
            {
                dis[v]=dis[u]+1;
                if(v!=T)    q.push(v);
            }
        }
    }
    return dis[T];
}
int dfs(int u,int FLOW)
{
    if(u==T)    return FLOW;
    int VAL=0;
    for(int i=head[u];i;i=nex[i])
    {
        int v=ver[i];
        if(dis[v]==dis[u]+1&&flow[i])
        {
            int tmp=dfs(v,min(FLOW,flow[i]));
            if(!tmp)    dis[v]=0;
            flow[i]-=tmp;    flow[i^1]+=tmp;
            VAL+=tmp;    FLOW-=tmp;
            if(!FLOW)    break;
        }
    }
    return VAL;
}
void tarjan(int u)
{
    dfn[u]=low[u]=++cnt;    t[++top]=u;
    for(int i=head[u];i;i=nex[i])
    {
        if(!flow[i])    continue;
        int v=ver[i];
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(!col[v])
            low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u])
    {
        ++sum;
        while(t[top+1]!=u)
            col[t[top--]]=sum;
    }
}
int main()
{
    n=read();    m=read();    S=read();    T=read();
    for(int i=1;i<=m;++i)
    {
        x=read();    y=read();    z=read();
        ++tot;nex[tot]=head[x];head[x]=tot;ver[tot]=y;flow[tot]=z;
        ++tot;nex[tot]=head[y];head[y]=tot;ver[tot]=x;flow[tot]=0;
    }
    while(bfs())    dfs(S,1<<30);
    for(int i=1;i<=n;++i)    if(!dfn[i])    tarjan(i);
    for(int i=2;i<=tot;i+=2)
        if(!flow[i])
        {
            if(col[ver[i]]!=col[ver[i^1]])    printf("1 ");
            else    printf("0 ");
            if(col[S]==col[ver[i^1]]&&col[ver[i]]==col[T])    printf("1\n");
            else    printf("0\n");
        }
        else
            printf("0 0\n");
    return 0;
}
View Code

 

 

posted @ 2019-05-17 11:12  Hevix  阅读(222)  评论(0编辑  收藏  举报