【洛谷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\)
因此我們構造指數型生成函式\(\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;
}