省选测试47 T2宝石(P5401 [CTS2019]珍珠) 题解

算法一

定义 (f[i][j]) 表示前 (i) 个珍珠,个数为奇数的种类有 (j) 种,这样状态是 (n*D) 的,转移是 (O(1)) 的,直接讨论当前选的的颜色是在奇数的 (j) 种中还是偶数的 ((D-j)) 种中

答案即为 (sum_{i=0}^{n-m*2}f[n][i])

复杂度 (O(n*D)) ,期望得分 (52)

算法二

(D leq 300,n,m leq 10^9)

按照算法一的定义,矩阵快速幂+极致卡常

这一部分复杂度是 (O(D^3*logn)) ,结合算法一期望得分 (60)

算法三

特判 (m=0) 的,(ans=D^n)(m=1) 的, (ans=D^n-A_D^n)

这一部分复杂度 (O(1)) ,结合算法一,二,三,期望得分 (64)

算法四

二项式反演+生成函数

(n-m*2) 即为合法情况下,最多有几种宝石的个数为奇数

首先特判掉 (n-m*2<0,ans=0)(n-m*2geq D,ans=D^n)

定义 (f_i) 表示 (D) 种宝石,恰好 (i) 种个数为奇数的方案数

(g_i) 表示 (D) 种宝石,钦定 (i) 种个数为奇数,其余的任意选的方案数(至少 (i) 种为奇数)

对于一种颜色, (cnt) 为奇数的方案数对应的 (EGF)(frac{e^x-e^{-x}}{2})(cnt) 任意的方案数对应的 (EGF)(e^x)

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

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

二项式定理展开 ((e^x-e^{-x})^i)

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

提出 (-1) 然后合并 (e) 的幂

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

((e^x)^{D-2(i-j)}) (系数为 (frac{[D-2(i-j)]^n}{n!}) )和组合数展开

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

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

换个枚举量,枚举 (i-j)

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

(sum) 后面就是卷积的形式,直接 (NTT) 算就好了

得到了 (g),然后需要二项式反演求出 (f),但是不能直接 (2)(for) 循环去求,那样是 (O(d^2))

注意反演的式子

[f_i=sum_{j=i}^{D}inom{j}{i}(-1)^{j-i}g_j ]

[f_i=frac{1}{i!}sum_{j=i}^{D}frac{j!}{(j-i)!}(-1)^{j-i}g_j ]

[f_i=frac{1}{i!}sum_{j=i}^{D}frac{(-1)^{j-i}}{(j-i)!}j!g_j ]

后面又是一个卷积,但是是差一定,所以枚举 (j)(0)(D-i)(NTT) 求出 (Ans_{D-i}=sum_{j=0}^{D-i}A_jB_{D-i-j})

其中 (A_i=frac{(-1)^i}{i!})(B_{D-i}=i!g_i)

那么 (f_i=frac{1}{i!}Ans_{D-i})

[ans=sum_{i=0}^{n-m*2}f_i ]

复杂度 (O(DlogD)) ,期望得分 (100)

代码
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;

const int maxn=1<<18|10,mod=998244353,Gi=332748118,G=3;
int n,m,D;
int rev[maxn],a[maxn],b[maxn],f[maxn],g[maxn],fac[maxn],fy[maxn];

int fp(int a,int x,int ans=1){
	for(;x;x>>=1,a=1ll*a*a%mod)	if(x&1) ans=1ll*ans*a%mod;
	return ans;
}

void NTT(int *a,int lim,int opt){
	for(int i=0;i<lim;++i) if(i<rev[i]) swap(a[i],a[rev[i]]);
	for(int d=1;d<lim;d<<=1){
		int st=d<<1,w1=fp(opt==-1?Gi:G,(mod-1)/st);
		for(int i=0;i<lim;i+=st){
			int w=1;
			for(int j=0;j<d;++j,w=1ll*w*w1%mod){
				int x=a[i+j],y=1ll*w*a[i+j+d]%mod;
				a[i+j]=(x+y)%mod;
				a[i+j+d]=(x+mod-y)%mod;
			}
		}
	}
	if(opt!=-1) return;
	for(int i=0,inv=fp(lim,mod-2);i<lim;++i) a[i]=1ll*a[i]*inv%mod;
}

void Init(int n){
	fac[0]=fy[0]=1;
	for(int i=1;i<=n;++i) fac[i]=1ll*fac[i-1]*i%mod;
	fy[n]=fp(fac[n],mod-2);
	for(int i=n;i>1;--i) fy[i-1]=1ll*fy[i]*i%mod;
}

int main(){
	scanf("%d%d%d",&D,&n,&m);
	Init(D);
	if(n-2*m<0) return puts("0"),0;
	if(n-2*m>=D) return printf("%d
",fp(D,n)),0;
	
	for(int i=0;i<=D;++i){
		if(i&1) a[i]=1ll*(mod-fp((D-2*i+mod)%mod,n))*fy[i]%mod;
		else a[i]=1ll*fp((D-2*i+mod)%mod,n)*fy[i]%mod;
		b[i]=fy[i];
	}
	int lim=1,bit=0;
	while(lim<=D*2) lim<<=1,++bit; --bit;
	for(int i=0;i<lim;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<bit);
	NTT(a,lim,1),NTT(b,lim,1);
	for(int i=0;i<lim;++i) a[i]=1ll*a[i]*b[i]%mod;
	NTT(a,lim,-1);
	for(int i=0;i<=D;++i) g[i]=1ll*fac[D]*fy[D-i]%mod*fp(fp(2,i),mod-2)%mod*a[i]%mod;
	
	for(int i=0;i<=D;++i){
		if(i&1) a[i]=mod-fy[i];
		else a[i]=fy[i];
		b[D-i]=1ll*fac[i]*g[i]%mod;
	}
	for(int i=D+1;i<lim;++i) a[i]=b[i]=0;
	NTT(a,lim,1),NTT(b,lim,1);
	for(int i=0;i<lim;++i) a[i]=1ll*a[i]*b[i]%mod;
	NTT(a,lim,-1);
	for(int i=0;i<=D;++i) f[i]=1ll*a[D-i]*fy[i]%mod;
	
	int ans=0;
	for(int i=0;i<=n-2*m;++i) (ans+=f[i])%=mod;
	printf("%d
",(ans+mod)%mod);
	return 0;
}
原文地址:https://www.cnblogs.com/Lour688/p/14575165.html