zoukankan      html  css  js  c++  java
  • [CTS2019]珍珠

    传送门

    一个长度为(n)的序列,每个位置可以自由填(1-D),问有多少种情况使得序列中可以找出(m)对相同的数

    假设数字(i)出现了(sum_i)次,那么需要满足

    [sumlimits_{i=1}^{D}lfloorfrac{sum_i}{2} floorge m ]

    [sumlimits_{i=1}^{D}frac{sum_i-sum_i\%2}{2}ge m ]

    [sumlimits_{i=1}^{D}sum_i-sum_i\%2ge 2*m ]

    [n-sumlimits_{i=1}^{D}sum_i\%2ge 2*m ]

    [sumlimits_{i=1}^{D}sum_i\%2le n-2*m ]

    设恰好有(i)个颜色数为奇数的方案数为(g_i),那么(ans=sumlimits_{i=0}^{n-2m}g_i)

    (f_i)为有(i)种颜色数量是奇数,其他颜色数随便的方案数,可以得到

    [f_i=sumlimits_{j=i}^{D}dbinom{j}{i}g_j ]

    根据二项式反演有

    [g_i=sumlimits_{j=i}^{D}(-1)^{j-i}dbinom{j}{i}f_j ]

    考虑求一波(f_i)

    颜色出现次数为奇数的(EGF{0,1,0,1,0,1,……})(frac{e^x-e^{-x}}{2})

    其他颜色随便排列的(EGF{1,1,1,1,1,……})(e^x)

    根据(EGF)得到

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

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

    将中间二项式展开

    [=dbinom{D}{i}frac{n!}{2^i}[x^n]sumlimits_{j=0}^{i}dbinom{i}{j}(e^x)^{j}(-e^{-x})^{i-j}(e^x)^{D-i} ]

    [=dbinom{D}{i}frac{n!}{2^i}sumlimits_{j=0}^{i}dbinom{i}{j}(-1)^{i-j}[x^n]e^{(D-2(i-j))x} ]

    根据(e^{ax}=sumlimitsfrac{a^n}{n!}),代入得到

    [=dbinom{D}{i}frac{n!}{2^i}sumlimits_{j=0}^{i}dbinom{i}{j}(-1)^{i-j}frac{(D-2(i-j))^n}{n!} ]

    我们由枚举(j)变为枚举(i-j)得到

    [=dbinom{D}{i}frac{n!}{2^i}sumlimits_{j=0}^{i}dbinom{i}{j}(-1)^jfrac{(D-2j)^n}{n!} ]

    展开组合数

    [=frac{D!}{(D-i)!2^i}sumlimits_{j=0}^{i}frac{(-1)^j(D-2j)^n}{j!}*frac{1}{(i-j)!} ]

    显然右边是个卷积,可以(O(DlogD))(f_i)

    再考虑

    [g_i=sumlimits_{j=i}^{D}(-1)^{j-i}dbinom{j}{i}f_j ]

    将组合数拆开

    [g_i=sumlimits_{j=i}^{D}(-1)^{j-i}frac{j!}{i!(j-i)!}f_j ]

    [g_i=frac{1}{i!}sumlimits_{j=0}^{D-i}frac{(-1)^j}{j!}(i+j)!f_{i+j} ]

    (a_i=frac{(-1)^i}{i!},b_i=i!f_i)(a^{'})(a)的翻转,得到

    [c_{D+i}=sumlimits_{j=0}^{D-i}frac{(-1)^j}{j!}(i+j)!f_{i+j}=sumlimits_{j=0}^{D-i}a^{'}_{D-j}b_{i+j} ]

    也是一个卷积,可以(O(DlogD))求解

    #include<bits/stdc++.h>
    using namespace std;
    namespace red{
    #define int long long
    #define ls(p) (p<<1)
    #define rs(p) (p<<1|1)
    #define lowbit(i) ((i)&(-i))
    	inline int read()
    	{
    		int x=0;char ch,f=1;
    		for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    		if(ch=='-') f=0,ch=getchar();
    		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    		return f?x:-x;
    	}
    	const int N=4e5+10,p=998244353,inv2=(p+1)>>1;
    	int D,n,m,ans;
    	int fac[N],inv[N];
    	int f[N],g[N];
    	int limit=1,len;
    	int pos[N];
    	inline int fast(int x,int k)
    	{
    		int ret=1;
    		while(k)
    		{
    			if(k&1) ret=ret*x%p;
    			x=x*x%p;
    			k>>=1;
    		}
    		return ret;
    	}
    	inline void ntt(int *a,int inv)
    	{
    		for(int i=0;i<limit;++i)
    			if(i<pos[i]) swap(a[i],a[pos[i]]);
    		for(int mid=1;mid<limit;mid<<=1)
    		{
    			int Wn=fast(3,(p-1)/(mid<<1));
    			for(int r=mid<<1,j=0;j<limit;j+=r)
    			{
    				int w=1;
    				for(int k=0;k<mid;++k,w=w*Wn%p)
    				{
    					int x=a[j+k],y=w*a[j+k+mid]%p;
    					a[j+k]=(x+y)%p;
    					a[j+k+mid]=(x-y+p)%p;
    				}
    			}
    		}
    		if(inv) return;
    		inv=fast(limit,p-2);reverse(a+1,a+limit);
    		for(int i=0;i<limit;++i) a[i]=a[i]*inv%p;
    	}
    	inline void main()
    	{
    		D=read(),n=read(),m=read();
    		if(D<=n-2*m) return(void)(printf("%lld
    ",fast(D,n)));
    		if(2*m>n) return(void)puts("0");
    		for(int i=fac[0]=1;i<=D;++i) fac[i]=fac[i-1]*i%p;
    		inv[D]=fast(fac[D],p-2);
    		for(int i=D-1;~i;--i) inv[i]=inv[i+1]*(i+1)%p;
    		for(int i=0;i<=D;++i) f[i]=fast((D-2*i+p)%p,n)*(i&1?p-inv[i]:inv[i])%p;
    		for(int i=0;i<=D;++i) g[i]=inv[i];
    		while(limit<=2*D) limit<<=1,++len;
    		for(int i=1;i<limit;++i) pos[i]=(pos[i>>1]>>1)|((i&1)<<(len-1));
    		ntt(f,1);ntt(g,1);
    		for(int i=0;i<limit;++i) f[i]=f[i]*g[i]%p;
    		ntt(f,0);
    		for(int i=0;i<=D;++i) f[i]=f[i]*fac[D]%p*fac[i]%p*inv[D-i]%p*fast(inv2,i)%p;
    		for(int i=0;i<=D;++i) g[D-i]=(i&1)?p-inv[i]:inv[i];
    		for(int i=D+1;i<limit;++i) f[i]=g[i]=0;
    		ntt(f,1);ntt(g,1);
    		for(int i=0;i<limit;++i) f[i]=f[i]*g[i]%p;
    		ntt(f,0);
    		for(int i=0;i<=n-2*m;++i) ans=(ans+f[i+D]*inv[i])%p;
    		printf("%lld
    ",ans);
    	}
    }
    signed main()
    {
    	red::main();
    	return 0;
    }
    
  • 相关阅读:
    ssd笔记
    深度学习 参数笔记
    NVIDIA驱动安装
    下载大文件笔记
    vue中使用echart笔记
    torch.no_grad
    暑期第二周总结
    暑期第一周总结
    第十六周学习进度
    期末总结
  • 原文地址:https://www.cnblogs.com/knife-rose/p/13044542.html
Copyright © 2011-2022 走看看