1. 程式人生 > 實用技巧 >【洛谷5401】[CTS2019] 珍珠(指數型生成函式+NTT)

【洛谷5401】[CTS2019] 珍珠(指數型生成函式+NTT)

點此看題面

  • \(n\)個球和\(D\)種顏色。
  • 問你有多少種染色方案,使得能選出至少\(m\)對同色的球。
  • \(D\le10^5,m\le n\le10^9\)

基礎轉化

\(cnt_x\)表示顏色為\(x\)的小球個數,那麼題意就相當於是:

\[\sum_{i=1}^D\lfloor\frac{cnt_x}2\rfloor\ge m \]

對於整除有一個基本的轉化\(\lfloor\frac x2\rfloor=\frac{x-x\%2}2\),因此就有:

\[\sum_{i=1}^D\frac{cnt_x-cnt_x\%2}2\ge m\\ \sum_{i=1}^D(cnt_x-cnt_x\%2)\ge 2m \]

由於\(\sum_{i=1}^Dcnt_x=n\),所以最終得到:

\[\sum_{i=1}^Dcnt_x\%2\le n-2m \]

也就是有至多\(n-2m\)種顏色出現奇數次

二項式反演

\(f_i\)表示有至少\(i\)種顏色出現奇數次,\(g_i\)表示有恰好\(i\)種顏色出現奇數次,顯然最終答案應該是\(\sum_{i=0}^{n-2m}g_i\)

\(f_i\)\(g_i\)之間有一個顯然的關係式:

\[f_i=\sum_{j=i}^DC_j^i\times g_j \]

根據二項式反演的式子得到:

\[g_i=\sum_{j=i}^D(-1)^{j-i}\times C_j^i\times f_j \]

考慮轉化一下這個式子,首先拆開組合數並移項:

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

構造兩個多項式\(A(x)=\sum_{i=0}^{D}(f_i\times i!)x^i,B(x)=\sum_{i=0}^D\frac{(-1)^{D-i}}{(D-i)!}x^i\)(注意\(B(x)\)的係數經過了翻轉,以形成一個卷積的形式)

\(A(x)*B(x)\)\(D+i\)次項係數就是\(g_i\times i!\)

那麼現在的問題就變成了如何求\(f_i\)

指數型生成函式

顯然,對於一個已知的\(cnt\)

陣列,生成它的方案數是\(\frac{n!}{\prod_{i=1}^D(cnt_i!)}\)

因此我們構造指數型生成函式\(\sum_{i=0}^{+\infty}\frac{x^i}{i!}=e^x\)

而現在我們要有至少\(i\)種顏色出現奇數次,那麼我們就要強制選\(i\)種顏色出來讓它出現奇數次。

考慮這\(i\)種顏色的生成函式實際上就是\(\frac{e^x-e^{-x}}2\)\(e^x\)\(e^{-x}\)相減剛好能消去偶次項)。

那麼得到計算\(f_i\)的樸素式子就應該是:

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

對於其中\((\frac{e^x-e^{-x}}2)^i\)一項,我們提出總分母\(2^i\),然後暴力二項式定理展開得到:

\[f_i=\frac{C_D^i\times n!}{2^i}\times [x^n](\sum_{j=0}^iC_i^j(e^x)^j(-e^{-x})^{i-j})(e^x)^{D-i} \]

簡單地化簡一下:

\[f_i=\frac{C_D^i\times n!}{2^i}\times \sum_{j=0}^iC_i^j(-1)^{i-j}[x^n]((e^x)^j(e^{-x})^{i-j})(e^x)^{D-i}\\ f_i=\frac{C_D^i\times n!}{2^i}\times \sum_{j=0}^iC_i^j(-1)^{i-j}[x^n]e^{(D-2(i-j))x} \]

現在含\(e\)的項就只有\(e^{(D-2(i-j))x}\)這個簡單的式子了。

考慮\(e^{ax}=\sum_{i=0}^{+\infty}\frac{a^ix^i}{i!}\),所以\([x^n]e^{ax}=\frac{a^n}{n!}\)

即,對於原式可以進一步得到:

\[f_i=\frac{C_D^i\times n!}{2^i}\times \sum_{j=0}^iC_i^j(-1)^{i-j}\frac{(D-2(i-j))^n}{n!} \]

整理一下,把它表示成卷積的形式就有:

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

構造兩個多項式\(A(x)=\sum_{i=0}^{D}\frac{(-1)^i\times(D-2i)^n}{i!}x^i,B(x)=\sum_{i=0}^D\frac{x^i}{i!}\)

顯然\(f_i=\frac{D!}{(D-i)!\times 2^i}\times [x^i](A(x)*B(x))\)

求出\(f_i\)之後代回到前面的式子中,再做一次\(NTT\)求出\(g_i\),這道題就做完了。

程式碼:\(O(Dlogn)\)

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define SZ 100000
#define X 998244353
#define I2 499122177
using namespace std;
int n,m,D,Fac[SZ+5],IFac[SZ+5],f[SZ+5],A[SZ<<2],B[SZ<<2];
I int QP(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
namespace Poly//多項式
{
	#define PR 3
	int P,L,R[SZ<<2];I void NTT(int* s,CI op)//NTT
	{
		RI i,j,k,x,y,U,S;for(i=0;i^P;++i) i<R[i]&&(x=s[i],s[i]=s[R[i]],s[R[i]]=x);
		for(i=1;i^P;i<<=1) for(U=QP(QP(PR,op),(X-1)/(i<<1)),j=0;j^P;j+=i<<1) for(S=1,k=0;
			k^i;++k,S=1LL*S*U%X) s[j+k]=((x=s[j+k])+(y=1LL*S*s[i+j+k]%X))%X,s[i+j+k]=(x-y+X)%X;
	}
	I void Mul(CI n,int* A,int* B)//卷積
	{
		RI i;P=1,L=0;W(P<=(n<<1)) P<<=1,++L;for(i=0;i^P;++i) R[i]=((R[i>>1]>>1)|((i&1)<<L-1));
		for(NTT(A,1),NTT(B,1),i=0;i^P;++i) A[i]=1LL*A[i]*B[i]%X;
		RI t=QP(P,X-2);for(NTT(A,X-2),i=0;i<=2*n;++i) A[i]=1LL*A[i]*t%X;
	}
}
int main()
{
	RI i;if(scanf("%d%d%d",&D,&n,&m),2*m>n) return puts("0"),0;//特判
	if(2*m<=n-D) return printf("%d",QP(D,n)),0;//特判
	for(Fac[0]=i=1;i<=D;++i) Fac[i]=1LL*Fac[i-1]*i%X;//預處理階乘
	for(IFac[D]=QP(Fac[D],X-2),i=D;i;--i) IFac[i-1]=1LL*IFac[i]*i%X;//預處理階乘逆元
	for(i=0;i<=D;++i) A[i]=1LL*(i&1?X-1:1)*QP((D-2*i+X)%X,n)%X*IFac[i]%X,B[i]=IFac[i];//第一遍卷積
	for(Poly::Mul(D,A,B),i=0;i<=D;++i) f[i]=1LL*A[i]*Fac[D]%X*IFac[D-i]%X*QP(I2,i)%X;//求出f[i]
	memset(A,0,sizeof(A)),memset(B,0,sizeof(B));//清空陣列
	for(i=0;i<=D;++i) A[i]=1LL*f[i]*Fac[i]%X,B[D-i]=1LL*(i&1?X-1:1)*IFac[i]%X;//第二遍卷積
	RI t=0;for(Poly::Mul(D,A,B),i=0;i<=n-2*m;++i) t=(1LL*A[D+i]*IFac[i]+t)%X;//求出g[i]並統計答案
	return printf("%d\n",t),0;
}