省选测试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*2\geq 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=\binom{D}{i}n![x^n](\frac{e^x-e^{-x}}{2})^i(e^x)^{D-i} \]

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

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

\[g_i=\binom{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=\binom{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}\binom{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\n",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\n",(ans+mod)%mod);
	return 0;
}
posted @ 2021-03-24 21:16  liuzhaoxu  阅读(92)  评论(2编辑  收藏  举报