Sensing a second field Noi2016 ten even - Dark (binomial theorem / Stirling Number + CDQ + NTT)

Sensing a second field Noi2016 ten even - Dark (binomial theorem / Stirling Number + CDQ + NTT)

The meaning of problems: n-free points, each side may exist to FIG, a FIG weight is the number of blocks m-th power of communication, find all possible values ​​of weights and FIG.

Consider \ (dp [i] [j ] \) represents \ (J \) points, a weight of \ (I \) th

We first pre-out \ (\ n-) points to the number of non-connected graph of \ (G [I] \) , the title template: BZOJ-3456 explanations

For \ (DP [I] [J] \) , enumeration \ (1 \) communication block size number of point as \ (X \) , it is possible to obtain \ (dp [i] [j ] = \ DP SUM [K] [JX] \ CDOT C (-J. 1,. 1-X) \ CDOT C (I, K) \ CDOT G [X] \) (each transition a communication block, developed with binomial theorem to find th)

Use \ (CDQ + NTT \) to complete the transfer, template question: HDU-5730 solution to a problem

#include<bits/stdc++.h>
using namespace std;

//#define int long long

#define reg register
typedef long long ll;
#define rep(i,a,b) for(reg int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(reg int i=a,i##end=b;i>=i##end;--i)
#define Mod2(x) ((x<0)&&(x+=P))
#define Mod1(x) ((x>=P)&&(x-=P))

template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }

char IO;
int rd(){
    int s=0,f=0;
    while(!isdigit(IO=getchar())) if(IO=='-') f=1;
    do s=(s<<1)+(s<<3)+(IO^'0');
    while(isdigit(IO=getchar()));
    return f?-s:s;
}

const int N=1<<15|5,P=998244353;


bool be;
int n=3e4,m=15;
int Inv[N],Fac[N];
ll qpow(ll x,ll k) {
    ll res=1;
    for(;k;k>>=1,x=x*x%P) if(k&1) res=res*x%P;
    return res;
}

int g[N],h[N],dp[16][N],w[N];
int A[16][N],B[N];
int rev[N];
void NTT(int n,int *a,int f) {
    rep(i,1,n-1) if(i<rev[i]) swap(a[i],a[rev[i]]);
    for(reg int i=1;i<n;i<<=1) {
        int len=n/i/2;
        for(reg int l=0;l<n;l+=2*i) {
            for(reg int j=l;j<l+i;j++) {
                int t=1ll*a[j+i]*w[(j-l)*len]%P;
                a[j+i]=a[j]-t; Mod2(a[j+i]);
                a[j]=a[j]+t; Mod1(a[j]);
            }
        }
    }
    if(f==-1) {
        ll base=qpow(n,P-2);
        rep(i,0,n-1) a[i]=a[i]*base%P;
    }
}

//预处理n个点联通图的数量g
void Solve1(int l,int r) {
    if(l==r) return;
    int mid=(l+r)>>1;
    Solve1(l,mid);
    int R=1,cc=-1;
    while(R<=r-l+1) R<<=1,cc++;
    rep(i,1,R) rev[i]=(rev[i>>1]>>1)|((i&1)<<cc);
    w[0]=1,w[1]=qpow(3,(P-1)/R);
    rep(i,2,R-1) w[i]=1ll*w[i-1]*w[1]%P;
    rep(i,0,R) A[0][i]=B[i]=0;
    rep(i,l,mid) A[0][i-l]=1ll*g[i]*Inv[i-1]%P;
    rep(i,1,r-l) B[i]=1ll*Inv[i]*h[i]%P;
    NTT(R,B,1),NTT(R,A[0],1);
    rep(i,0,R-1) A[0][i]=1ll*A[0][i]*B[i]%P;
    w[0]=1,w[1]=qpow((P+1)/3,(P-1)/R);
    rep(i,2,R-1) w[i]=1ll*w[i-1]*w[1]%P;
    NTT(R,A[0],-1);
    rep(i,mid+1,r) g[i]=(g[i]-1ll*A[0][i-l]*Fac[i-1]%P+P)%P;
    Solve1(mid+1,r);
}

int C[20][20];
void Solve(int l,int r) {
    if(l==r) return;
    int mid=(l+r)>>1;
    Solve(l,mid);
    int R=1,cc=-1;
    while(R<=r-l+1) R<<=1,cc++;
    rep(i,1,R) rev[i]=(rev[i>>1]>>1)|((i&1)<<cc);
    w[0]=1,w[1]=qpow(3,(P-1)/R);
    rep(i,2,R-1) w[i]=1ll*w[i-1]*w[1]%P;
    rep(i,0,R) B[i]=0;
    rep(i,1,r-l) B[i]=1ll*Inv[i-1]*g[i]%P;
    NTT(R,B,1);
    rep(i,0,15) {
        rep(j,0,R) A[i][j]=0;
        rep(j,l,mid) A[i][j-l]=1ll*dp[i][j]*Inv[j]%P;
        NTT(R,A[i],1);
        rep(j,0,R-1) A[i][j]=1ll*A[i][j]*B[j]%P;
    }
    w[0]=1,w[1]=qpow((P+1)/3,(P-1)/R);
    rep(i,2,R-1) w[i]=1ll*w[i-1]*w[1]%P;
    rep(i,0,15) {
        NTT(R,A[i],-1);
        rep(j,mid+1,r) A[i][j-l]=1ll*A[i][j-l]*Fac[j-1]%P;
    }
    rep(i,mid+1,r) rep(j,0,15) rep(k,0,j) dp[j][i]=(dp[j][i]+1ll*C[j][k]*A[k][i-l])%P;
    Solve(mid+1,r);
}


bool ed;
int main(){
    freopen("dark.in","r",stdin),freopen("dark.out","w",stdout);
    Fac[0]=Fac[1]=Inv[0]=Inv[1]=1;
    rep(i,2,n) {
        Fac[i]=1ll*Fac[i-1]*i%P;
        Inv[i]=1ll*(P-P/i)*Inv[P%i]%P;
    }
    rep(i,2,n) Inv[i]=1ll*Inv[i]*Inv[i-1]%P;
    rep(i,0,0) dp[i][0]=1;
    rep(i,0,n) g[i]=h[i]=qpow(2,i*(i-1)/2);
    rep(i,0,m) {
        C[i][0]=1;
        rep(j,1,i)  C[i][j]=(C[i-1][j]+C[i-1][j-1])%P;
    }
    Solve1(1,n);
    Solve(0,n);
    rep(kase,1,rd()) {
        n=rd(),m=rd();
        printf("%d\n",dp[m][n]);
    }
}

Guess you like

Origin www.cnblogs.com/chasedeath/p/12106697.html
Recommended