zoukankan      html  css  js  c++  java
  • [LOJ3120][CTS2019|CTSC2019]珍珠:生成函数+NTT

    分析

    容易发现(D leq n - 2m)时,任意数列都满足要求,直接判掉,下文所讨论的均为(D > n - 2m)的情况。

    考虑把两个数列合并,显然可以认为是两个带标号对象的合并,可以使用EGF相乘。

    我们可以枚举有(k)个数出现了奇数次,答案即为:

    [egin{aligned} ans=&n!sum_{k=0}^{n-2m}(EVEN(x)+yODD(x))^D[x^n][y^k]\ =&n!sum_{k=0}^{n-2m}(frac{e^x+e^{-x}}{2}+yfrac{e^x-e^{-x}}{2})^D[x^n][y^k]\ =&n!frac{1}{2^D}sum_{k=0}^{n-2m}((e^x+e^{-x})+y(e^x-e^{-x}))^D[x^n][y^k]\ =&n!frac{1}{2^D}sum_{k=0}^{n-2m}(e^x(1+y)+e^{-x}(1-y))^D[x^n][y^k]\ =&n!frac{1}{2^D}sum_{k=0}^{n-2m}sum_{i=0}^{D}inom{D}{i}e^{(2i-D)x}(1+y)^i(1-y)^{D-i}[x^n][y^k]\ =&frac{1}{2^D}sum_{k=0}^{n-2m}sum_{i=0}^{D}inom{D}{i}(2i-D)^n(1+y)^i(1-y)^{D-i}[y^k]\ =&frac{1}{2^D}sum_{i=0}^{D}inom{D}{i}(2i-D)^nsum_{k=0}^{n-2m}(1+y)^i(1-y)^{D-i}[y^k]\ end{aligned} ]

    (以下部分参考了bestfy的博客。)

    现在我们需要对(forall i in [0,D]),求出(f(i)=sum_{k=0}^{n-2m}(1+y)^i(1-y)^{D-i}[y^k])

    (i < D)时,

    [egin{aligned} f(i)=&sum_{k=0}^{n-2m}(1+y)^i(1-y)^{D-i}[y^k]\ =&(1+y)^i(1-y)^{D-i}(1+y+y^2+...)[y^{n-2m}]\ =&(1+y)^i(1-y)^{D-i-1}[y^{n-2m}]\ =&sum_{j=0}^{n-2m}inom{i}{j}inom{D-i-1}{n-2m-j}(-1)^{n-2m-j}\ end{aligned} ]

    上式可以化成卷积的形式然后NTT。

    (i = D)时,

    [f(D)=sum_{k=0}^{n-2m}(1+y)^D[y^k] ]

    因为(D>n-2m),所以这个东西可以直接暴力算。

    代码

    #include <bits/stdc++.h>
    
    #define rin(i,a,b) for(int i=(a);i<=(b);++i)
    #define irin(i,a,b) for(int i=(a);i>=(b);--i)
    #define trav(i,a) for(int i=head[a];i;i=e[i].nxt)
    #define Size(a) (int)a.size()
    #define pb push_back
    #define mkpr std::make_pair
    #define fi first
    #define se second
    #define lowbit(a) ((a)&(-(a)))
    typedef long long LL;
    
    using std::cerr;
    using std::endl;
    
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    
    const int MAXN=100005;
    const int MOD=998244353;
    const int NTT=1048576;
    const int G=3;
    const int INVG=332748118;
    
    int D,N,M,n,m,len,rev[MAXN<<2];
    int fac[MAXN],invf[MAXN];
    int w[NTT+5],iw[NTT+5];
    int A[MAXN<<2],B[MAXN<<2];
    
    inline int qpow(int x,int y){
    	int ret=1,tt=x%MOD;
    	while(y){
    		if(y&1)ret=1ll*ret*tt%MOD;
    		tt=1ll*tt*tt%MOD;
    		y>>=1;
    	}
    	return ret;
    }
    
    inline int binom(int n,int m){
    	if(n<0||m<0||n<m)return 0;
    	return 1ll*fac[n]*invf[n-m]%MOD*invf[m]%MOD;
    }
    
    void ntt(int *c,int dft){
    	rin(i,0,n-1)if(i<rev[i])std::swap(c[i],c[rev[i]]);
    	for(int mid=1;mid<n;mid<<=1){
    		int r=(mid<<1),u=NTT/r;
    		for(int l=0;l<n;l+=r){
    			int v=0;
    			for(int i=0;i<mid;++i,v+=u){
    				int x=c[l+i],y=1ll*c[l+mid+i]*(dft>0?w[v]:iw[v])%MOD;
    				c[l+i]=x+y<MOD?x+y:x+y-MOD;
    				c[l+mid+i]=x-y>=0?x-y:x-y+MOD;
    			}
    		}
    	}
    	if(dft<0){
    		int invn=qpow(n,MOD-2);
    		rin(i,0,n-1)c[i]=1ll*c[i]*invn%MOD;
    	}
    }
    
    void prepare(){
    	for(n=1,len=0;n<=m;n<<=1,++len);
    	rin(i,1,n-1)rev[i]=((rev[i>>1]>>1)|((i&1)<<(len-1)));
    }
    
    void init(int N){
    	fac[0]=1;
    	rin(i,1,N)fac[i]=1ll*fac[i-1]*i%MOD;
    	invf[N]=qpow(fac[N],MOD-2);
    	irin(i,N-1,0)invf[i]=1ll*invf[i+1]*(i+1)%MOD;
    	w[0]=iw[0]=1;
    	w[1]=qpow(G,(MOD-1)/NTT),iw[1]=qpow(INVG,(MOD-1)/NTT);
    	rin(i,2,NTT-1){
    		w[i]=1ll*w[i-1]*w[1]%MOD;
    		iw[i]=1ll*iw[i-1]*iw[1]%MOD;
    	} 
    }
    
    int main(){
    	D=read(),N=read(),M=read();int S=N-2*M;
    	if(M>N/2){printf("0
    ");return 0;}
    	if(D<=S){printf("%d
    ",qpow(D,N));return 0;}
    	init(D);
    	rin(i,0,S)A[i]=1ll*(((S-i)&1)?MOD-1:1)*invf[i]%MOD*invf[S-i]%MOD;
    	rin(i,0,D)if(D-1-S-i>=0)B[i]=1ll*invf[i]*invf[D-1-S-i]%MOD;
    	m=S+D;prepare();
    	ntt(A,1);ntt(B,1);
    	rin(i,0,n-1)A[i]=1ll*A[i]*B[i]%MOD;
    	ntt(A,-1);
    	int ans=0;
    	rin(i,0,D){
    		if(D-1-i>=0){
    			A[i]=1ll*A[i]*fac[i]%MOD*fac[D-i-1]%MOD;
    			ans=(ans+1ll*binom(D,i)*qpow(2*i-D,N)%MOD*A[i])%MOD; 
    		}
    		else{
    			int temp=0;
    			rin(j,0,S)temp=(temp+binom(D,j))%MOD;
    			ans=(ans+1ll*binom(D,i)*qpow(2*i-D,N)%MOD*temp)%MOD;
    		}
    	}
    	printf("%lld
    ",(1ll*ans*qpow(qpow(2,D),MOD-2)%MOD+MOD)%MOD);
    	return 0;
    }
    
  • 相关阅读:
    关于const_cast
    TinyXPath与TinyXML
    C++的异常
    如何让对象只能处于堆中
    股票的委托价、成交价与成本价的关系
    static_cast dynamic_cast reinterpret_cast const_cast
    C++ MD5,SHA1源码下载和简单调用
    C++中char[]转string
    HttpWorker
    winnet winhttp
  • 原文地址:https://www.cnblogs.com/ErkkiErkko/p/10903785.html
Copyright © 2011-2022 走看看