UOJ # 428. [2018] Team ordinary job title of count

# 428. [2018] Team ordinary job title of count

 

Good model into question

Count the number of labels have become so legitimate tree.

Legal restrictions:

1. Reference numeral root subtree is larger than

2. If the son is all the leaves, there are number of B

3. If there is a son, not a leaf, there are number of A

 

Then consider DP

The case of direct enumeration root son

cdq partition NTT is very disgusting

Not only is his own roll, or roll each other

After some simplification and translation, it can be converted into a form cdq partition NTT:

How how to do good.

Anyway, I finally pushed equation has the following characteristics (formulas do not write):

For convenience, Imperial g [0], f [0], g [1], f [1] is 0

For f, a fixed, a pan right moment, and then is cdq partition of the template title

For g, when partition sections l cdq not 0 to F as [l, mid], G as [ql, qr], and G as [l, mid], F as [ql, qr] do two all over

This is actually the rest g [n] = g [0] * f [n], but the g [0] = 0, so do not control

Code:

const int N=240000+5;
int jie[N],inv[N];
int f[N],g[N];
int n,sa,sb;
int ta[N],b[N],a[N];
void divi(int l,int r,int ql,int qr){
    // cout<<" divi "<<l<<" "<<r<<" ql "<<ql<<" qr "<<qr<<endl;
    if(l==0&&r==1){
        f[0]=f[1]=g[0]=g[1]=0;
        return;
    }
    if(l==r){
        f[l]=ad(mul(f[l],jie[l-1]),b[l-1]);
        g[l]=ad(f[l],mul(g[l],jie[l-1]));
        f[l]=mul(f[l],inv[l-1]);
        g[l]=mul(g[l],inv[l]);
        return;
    }
    int mid=(l+r)>>1;
    int qmd=(ql+qr)>>1;
    divi(l,mid,ql,qmd);
    Poly A,G;
    A.resize(qr-ql+1);
    G.resize(mid-l+1);
    for(reg i=ql;i<=qr;++i){
        A[i-ql]=a[i];
    }
    for(reg i=l;i<=mid;++i){
        G[i-l]=g[i];
    }
    A*=G;
    for(reg i=mid+1;i<=r;++i){
        f[i]=ad(f[i],A[i-l]);
    } 
    
    if(l==0){
        Poly F;G.clear();
        F.resize(mid-l+1);
        G.resize(mid-l+1);
        for(reg i=l;i<=mid;++i){
            F[i-l]=f[i];
            G[i-l]=g[i];
        }
        F=F*G;
        for(reg i=mid+1;i<=r;++i){
            g[i]=ad(g[i],F[i]);
        }
    }else{
        Poly F;G.clear();
        F.resize(qr-ql+1);
        G.resize(mid-l+1);
        for(reg i=l;i<=mid;++i){
            G[i-l]=g[i];
        }
        for(reg i=ql;i<=qr;++i){
            F[i-ql]=f[i];
        }
        F=F*G;
        for(reg i=mid+1;i<=r;++i){
            g[i]=ad(g[i],F[i-l]);
        }
        F.clear();G.clear();
        F.resize(mid-l+1);
        G.resize(qr-ql+1);
        for(reg i=ql;i<=qr;++i){
            G[i-ql]=g[i];
        }
        for(reg i=l;i<=mid;++i){
            F[i-l]=f[i];
        }
        F=F*G;
        for(reg i=mid+1;i<=r;++i){
            g[i]=ad(g[i],F[i-l]);
        }
    }
    divi(mid+1,r,ql,qmd);
}
int main(){
    rd(n);rd(sa);rd(sb);int x;
    for(reg i=1;i<=sa;++i){rd(x);ta[x]=1;}
    for(reg i=1;i<=sb;++i){rd(x);b[x]=1;}
    if(n==1){
        puts("1");return 0;
    }
    int m;
    for(m=1;m<=n;m<<=1);
    jie[0]=1;
    for(reg i=1;i<=m;++i) jie[i]=mul(jie[i-1],i);
    inv[m]=qm(jie[m],mod-2);
    for(reg i=m-1;i>=0;--i) inv[i]=mul(inv[i+1],i+1);

    for(reg i=1;i<=m;++i){
        a[i]=mul(ta[i-1],inv[i-1]);
    }
    a[0]=0;

    divi(0,m-1,0,m-1);
    ll ans=f[n];
    ans=mul(ans,jie[n-1]);
    ot(ans);
    return 0;
}

树形结构很巧妙啊

f,g互相卷的分治NTT第一次写,还是举一个0,1,2,3,4,5,6,7的例子最好理解了!

 

Guess you like

Origin www.cnblogs.com/Miracevin/p/10994486.html