• 联考20200604 T2 宝石


    题目:


    分析:
    你竞赛就我不会生成函数了.jpg
    首先考虑(O(nD))(DP),设(f[i][j]),表示确定了前(i)个珠子,有(j)种颜色为奇数的情况
    简单递推
    发现关键是求出(f[n][i]),由于(n)很大,删去这位,求(f_i)
    恰好貌似不好求,我们来求至少
    (g_i)为至少有(i)种颜色为奇数的方案数

    我们知道:

    [e^x=sum_{i=0}frac{x^i}{i!} ]

    [e^{-x}=sum_{i=0}(-1)^{i}frac{x^i}{i!} ]

    组合起来:
    某颜色有奇数个物品的生成函数(frac{e^x-e^{-x}}{2})
    某颜色有偶数个物品的生成函数(frac{e^x+e^{-x}}{2})

    那么(g)的生成函数我们可以表达为:

    [g_i=inom{D}{i}n![x^n](frac{e^x-e^{-x}}{2})^i e^{(D-i)x} ]

    中间二项式定理展开:

    [g_i=frac{inom{D}{i}n!}{2^i}[x^n]sum_{j=0}^{i}(-1)^jinom{i}{j}e^{(D-2i+2j)x} ]

    直接取第n项化出来得到:

    [g_i=frac{inom{D}{i}i!}{2^i}sum_{j=0}^{i}(-1)^jfrac{(D-2j)^n}{j!(i-j)!} ]

    发现是卷积形式大力NTT
    然后二项式反演再做一次NTT求得(f)
    取合法位置的值求和就是答案

    留下了没有数理基础的泪水.jpg

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    
    #define maxn 600005
    #define MOD 998244353
    #define G 3
    #define iG 332748118
    
    using namespace std;
    
    inline long long getint()
    {
    	long long num=0,flag=1;char c;
    	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
    	return num*flag;
    }
    
    int D,n,m,len=1;
    int fac[maxn],inv[maxn];
    int A[maxn],B[maxn],rev[maxn];
    
    inline int ksm(int num,int k)
    {
    	int ret=1;
    	for(;k;k>>=1,num=1ll*num*num%MOD)if(k&1)ret=1ll*ret*num%MOD;
    	return ret;
    }
    
    inline void NTT(int *a,int len,int op)
    {
    	for(int i=0;i<len;i++)if(i<rev[i])swap(a[i],a[rev[i]]);
    	for(int i=1;i<len;i<<=1)for(int j=0,wn=ksm(op==1?G:iG,(MOD-1)/(i<<1));j<len;j+=i<<1)
    		for(int k=0,w=1;k<i;k++,w=1ll*w*wn%MOD)
    		{
    			int x=a[j+k],y=1ll*a[i+j+k]*w%MOD;
    			a[j+k]=(x+y)%MOD,a[i+j+k]=(x-y)%MOD;
    		}
    	if(!~op)for(int i=0,Inv=ksm(len,MOD-2);i<len;i++)a[i]=1ll*a[i]*Inv%MOD;
    }
    
    inline void mul(int *A,int *B)
    {
    	NTT(A,len,1),NTT(B,len,1);
    	for(int i=0;i<len;i++)A[i]=1ll*A[i]*B[i]%MOD;
    	NTT(A,len,-1);
    }
    
    int main()
    {
    	D=getint(),n=getint(),m=getint();
    	while(len<=2*D)len<<=1;
    	for(int i=0;i<len;i++)rev[i]=(rev[i>>1]>>1)|(i&1?len>>1:0);
    	fac[0]=fac[1]=inv[0]=inv[1]=1;
    	for(int i=2;i<=D;i++)fac[i]=1ll*fac[i-1]*i%MOD;
    	for(int i=2;i<=D;i++)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
    	for(int i=2;i<=D;i++)inv[i]=1ll*inv[i]*inv[i-1]%MOD;
    	for(int i=0;i<=D;i++)A[i]=(i&1?-1ll:1ll)*ksm(D-2*i,n)%MOD*inv[i]%MOD;
    	for(int i=0;i<=D;i++)B[i]=inv[i];
    	mul(A,B);
    	for(int i=D+1;i<len;i++)A[i]=B[i]=0;
    	for(int i=0;i<=D;i++)A[i]=1ll*A[i]*fac[i]%MOD*inv[D-i]%MOD*fac[D]%MOD*ksm(inv[2],i)%MOD;
    	for(int i=0;i<=D;i++)B[D-i]=(i&1?-1:1)*inv[i];
    	mul(A,B);
    	int ans=1ll*inv[0]*A[D]%MOD;
    	for(int i=1;i<=min(n-2*m,D);i++)ans=(ans+1ll*inv[i]*A[D+i])%MOD;
    	printf("%d
    ",(ans+MOD)%MOD);
    }
    

  • 相关阅读:
    inspector 只读属性
    使用MongoDB
    【Roslyn C#】Runtime环境Unity读取字符串代码
    Unity使用LoadImage 读取byte[]图片时,会出现白边问题
    团队中避免不可维护代码的措施
    Unity点到线段的最短距离
    判断点是否在多边形内部
    Unity 根据前后帧位置自动旋转
    停止Unity在运行时脚本修改重新编译的情况
    KI子线段树 / AKEE SegmentTree
  • 原文地址:https://www.cnblogs.com/Darknesses/p/13046016.html
Copyright © 2020-2023  润新知