LibreOJ #3120.「CTS2019 | CTSC2019」珍珠 生成函数

题意

n n n个范围在 [ 1 , D ] [1,D] [1,D]之间的整数均匀随机变量,问能够选出 m m m对变量,满足每个变量至多只出现在一对变量中,且同一对变量的值相同的概率。
n , m ≤ 1 0 9 , D ≤ 1 0 5 n,m\le10^9,D\le10^5 n,m109,D105

分析

显然一个数值出现偶数次的 E G F EGF EGF e x + e − x 2 \frac{e^x+e^{-x}}{2} 2ex+ex,奇数次则为 e x − e − x 2 \frac{e^x-e^{-x}}{2} 2exex
那么答案就是 n ! ∑ k = 0 n − 2 m ( e x + e − x 2 + y e x − e − x 2 ) D [ x n ] [ y k ] n!\sum_{k=0}^{n-2m}(\frac{e^x+e^{-x}}{2}+y\frac{e^x-e^{-x}}{2})^D[x^n][y^k] n!k=0n2m(2ex+ex+y2exex)D[xn][yk]
= n ! 2 D ∑ k = 0 n − 2 m [ e x ( 1 + y ) + e − x ( 1 − y ) ] D [ x n ] [ y k ] =\frac{n!}{2^D}\sum_{k=0}^{n-2m}[e^x(1+y)+e^{-x}(1-y)]^D[x^n][y^k] =2Dn!k=0n2m[ex(1+y)+ex(1y)]D[xn][yk]
= n ! 2 D ∑ k = 0 n − 2 m ∑ i = 0 D C D i e ( 2 i − D ) x ( 1 + y ) i ( 1 − y ) D − i [ x n ] [ y k ] =\frac{n!}{2^D}\sum_{k=0}^{n-2m}\sum_{i=0}^DC_D^ie^{(2i-D)x}(1+y)^i(1-y)^{D-i}[x^n][y^k] =2Dn!k=0n2mi=0DCDie(2iD)x(1+y)i(1y)Di[xn][yk]
= 1 2 D ∑ i = 0 D C D i ( 2 i − D ) n ∑ k = 0 n − 2 m ( 1 + y ) i ( 1 − y ) D − i [ y k ] =\frac{1}{2^D}\sum_{i=0}^DC_D^i(2i-D)^n\sum_{k=0}^{n-2m}(1+y)^i(1-y)^{D-i}[y^k] =2D1i=0DCDi(2iD)nk=0n2m(1+y)i(1y)Di[yk]对于后面那部分有 ∑ k = 0 n − 2 m ( 1 + y ) i ( 1 − y ) D − i [ y k ] \sum_{k=0}^{n-2m}(1+y)^i(1-y)^{D-i}[y^k] k=0n2m(1+y)i(1y)Di[yk]
= ( 1 + y ) i ( 1 − y ) D − i ( 1 + y + y 2 + . . . ) [ y n − 2 m ] =(1+y)^i(1-y)^{D-i}(1+y+y^2+...)[y^{n-2m}] =(1+y)i(1y)Di(1+y+y2+...)[yn2m]
= ( 1 + y ) i ( 1 − y ) D − i 1 1 − y [ y n − 2 m ] =(1+y)^i(1-y)^{D-i}\frac{1}{1-y}[y^{n-2m}] =(1+y)i(1y)Di1y1[yn2m]
D = i D=i D=i时可以暴力求,当 D = ̸ i D=\not i D≠i时上式则等于 ( 1 + y ) i ( 1 − y ) D − i − 1 [ y n − 2 m ] (1+y)^i(1-y)^{D-i-1}[y^{n-2m}] (1+y)i(1y)Di1[yn2m]
二项式展开之后就变成了一个卷积形式,用 F F T FFT FFT直接做就好。
时间复杂度 O ( D l o g D ) O(DlogD) O(DlogD)

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

typedef long long LL;

const int N=400005;
const int MOD=998244353;

int n,m,D,jc[N],ny[N],a[N],b[N],rev[N],L;

int ksm(int x,int y)
{
	int ans=1;
	while (y)
	{
		if (y&1) ans=(LL)ans*x%MOD;
		x=(LL)x*x%MOD;y>>=1;
	}
	return ans;
}

int C(int n,int m)
{
	if (n<m) return 0;
	else return (LL)jc[n]*ny[m]%MOD*ny[n-m]%MOD;
}

void NTT(int *a,int f)
{
	for (int i=0;i<L;i++) if (i<rev[i]) std::swap(a[i],a[rev[i]]);
	for (int i=1;i<L;i<<=1)
	{
		int wn=ksm(3,f==1?(MOD-1)/i/2:MOD-1-(MOD-1)/i/2);
		for (int j=0;j<L;j+=(i<<1))
		{
			int w=1;
			for (int k=0;k<i;k++)
			{
				int u=a[j+k],v=(LL)a[j+k+i]*w%MOD;
				a[j+k]=(u+v)%MOD;a[j+k+i]=(u+MOD-v)%MOD;
				w=(LL)w*wn%MOD;
			}
		}
	}
	if (f==-1) for (int i=0,ny=ksm(L,MOD-2);i<L;i++) a[i]=(LL)a[i]*ny%MOD;
}

int main()
{
	scanf("%d%d%d",&D,&n,&m);
	jc[0]=jc[1]=ny[0]=ny[1]=1;
	for (int i=2;i<=D;i++) jc[i]=(LL)jc[i-1]*i%MOD,ny[i]=(LL)(MOD-MOD/i)*ny[MOD%i]%MOD;
	for (int i=2;i<=D;i++) ny[i]=(LL)ny[i-1]*ny[i]%MOD;
	int k=n-m*2,d=D-1;
	for (int i=0;i<=D;i++)
	{
		if (i<=k&&k-i<=D)
		{
			a[i]=(LL)ny[i]*ny[k-i]%MOD;
			if ((k-i)&1) a[i]=MOD-a[i];
		}
		if (d-k-i>=0) b[i]=(LL)ny[i]*ny[d-k-i]%MOD;
 	}
 	int lg=0;
 	for (L=1;L<=D*2;L<<=1,lg++);
 	for (int i=0;i<L;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1));
 	NTT(a,1);NTT(b,1);
 	for (int i=0;i<L;i++) a[i]=(LL)a[i]*b[i]%MOD;
 	NTT(a,-1);
 	int ans=0;
 	for (int i=0;i<D;i++) (ans+=(LL)C(D,i)*ksm(i*2-D,n)%MOD*jc[i]%MOD*jc[d-i]%MOD*a[i]%MOD)%=MOD;
 	for (int i=0;i<=std::min(D,k);i++) (ans+=(LL)C(D,i)*ksm(D,n)%MOD)%=MOD;
 	ans=(LL)ans*ksm(ksm(2,D),MOD-2)%MOD;
 	ans+=ans<0?MOD:0;
 	printf("%d\n",ans);
 	return 0;
 }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值