CTS2019 珍珠

CTS2019 珍珠

题意:

给定 \(n,m,D\),计算有多少个长度为 \(n\) 的序列,每个元素的值为 \([1,D]\),满足出现次数为奇数的颜色数小于 \(n-2m\) 的序列的数量。

\(n,m\le 10^9,D\le 10^5\)

Solution


时隔一年,我来补这个题的原官方题解做法和 djq 神仙的解法了。

这个题目前大致有三种主流做法,今天打算集体补一下(容斥原本会的,打算重新推一下)

Algorithm1

  • 容斥

\(f_i\) 表示单子数量恰好为 \(i\) 的序列的数量。

\(g_i\) 表示单子数量至少为 \(i\) 的序列的数量。

根据容斥理论,我们有:

\[g_i=\sum_{j\ge i}f_j\binom{j}{i} \]

于是有:

\[\begin{aligned} \\&f_i=\sum_{j\ge i}g_j\binom{j}{i}(-1)^{j-i} \\&\Rightarrow f_i\times i!(-1)^i=\sum_{j-k=i} g_j\frac{j!(-1)^j}{k!} \end{aligned}\]

于是执行一次差值卷积即可。

考虑 \(g_i\),不难注意到:

\[\begin{aligned} &g_k=\binom{D}{k}\Big(\frac{e^x-e^{-x}}{2}\Big)^ke^{(D-k)x}[x^n]\times n! \\&\Rightarrow \binom{D}{k}\frac{1}{2^k}\sum_i \binom{k}{i}(-1)^{k-i}e^{(2i+D)x}[x^n]\times n! \\&\Rightarrow \binom{D}{k}\frac{1}{2^k}\sum_i \frac{k!}{i!(k-i)!}(-1)^{k-i}(2i+D)^n) \\&\Rightarrow \frac{D!}{(D-k)!2^k}\sum_{i+j=k}\frac{(2i+D)^n}{i!}\times \frac{(-1)^j}{j!} \end{aligned}\]

可以卷积了。复杂度 \(\mathcal O(n\log n)\)


Algorithm2

原标算(大力生成函数,神仙组合意义转换,找规律,归纳)

\(m\leftarrow n-2m\),这样我们的表述将更为简洁。

考虑通过生成函数将答案直接写出来,我们有:

\[\begin{aligned} &\sum_{k=0}^{m}\binom{D}{k}\Big(\frac{e^{x}-e^{-x}}{2}\Big)^k\Big(\frac{e^x+e^{-x}}{2}\Big)^{D-k}[x^n]\times n! \\&\Rightarrow \frac{n!}{2^D}\sum_{k=0}^m \binom{D}{k}\sum_i e^{2i-k}(-1)^{k-i}\binom{k}{i}\sum_j \binom{D-k}{j}e^{2j-D+k}[x^n] \\&\Rightarrow \frac{1}{2^D}\sum_k^m\sum_i\sum_j \binom{D}{k}\binom{k}{i}\binom{D-k}{j}(2i+2j-D)^n(-1)^{k-i} \end{aligned}\]

接下来考虑 \(\binom{D}{k}\binom{k}{i}\binom{D-k}{j}\) 的组合意义。

等价于从 \(D\) 个球选 \(k\) 个再选 \(i\) 个,再从剩下的 \(D-k\) 个选 \(j\) 个的方案数。

也等价于先选 \(i+j\) 个出来,再选 \(i\) 个出来,剩下的归为 \(j\),再从 \(D-(i+j)\) 个中选 \(k-i\) 个出来。

于是有 \(\binom{D}{k}\binom{k}{i}\binom{D-k}{j}=\binom{D}{i+j}\binom{i+j}{i}\binom{D-i-j}{k-i}\)

枚举 \(i+j=t\),回代得到:

\[\begin{aligned} &\frac{1}{2^D}\sum_{t}\binom{D}{t}(2t-D)^n\sum_{k}^m\sum_i \binom{i+j}{i}\binom{D-i-j}{k-i}(-1)^{k-i} \end{aligned}\]

考虑后面的组合数的组合意义,等价于从 \((0,0)\) 出发走到 \((j,i)\),再走到 \((D-k,k)\) 处的方案数。

这样可以考虑通过生成函数来解决路径计数的问题,具体的,我们先会行走 \(t\) 步,每一步的贡献都是 \(1\),接下来我们走 \(D-t\) 步,每次走 \(y\) 贡献均为 \(-1\)

于是得到:

\[\begin{aligned} &\frac{1}{2^D}\sum_{t}\binom{D}{t}(2t-D)^n\sum_{k}^m (1+x)^t(1-x)^{D-t}[x^k] \end{aligned}\]

考虑设 \(F(t,D)=\sum_k^m (1+x)^t(1-x)^{D-t}[x^k]\)

我们发现 \(F(0,d)=\sum_k^m(1-x)^{d}[x^k]=\sum_k^m \binom{d}{k}(-1)^k\)

通过手玩/人类智慧极限,我们发现 \(F(0,0)=1,F(0,d)=(-1)^m\binom{d-1}{m}\)

具体论证可以通过帕斯卡定理来说明。

接下来我们进一步打表+手玩,发现 \(F(x,y)=2F(x-1,y-1)-F(x-1,y)\)

知道结论后论证其正确性是 naive 的,但是正向推导是困难的,所以还是建议打表找规律。

不过事实上在计算 \(F(1,6),F(2,6)...\) 这些值的时候其实就可以看出来了。

那么设 \(G_t(x)=\sum_k F(t,k)x^k\),不难发现 \(G_t(x)=G_{t-1}(x)(2x-1)\)

于是我们有:

\[G_t(x)=(2x-1)^tG_0(x) \]

其中,\(G_0(x)\) 是可以预处理的,设第 \(i\) 项系数为 \(g_i\)

于是我们有:

\[\begin{aligned} &F(t,D)=G_t(x)[x^D]=\sum_k 2^k(-1)^{t-k}\binom{t}{k}g_{D-k} \\&=F(t,D)=t!\sum_{k+j=t} \frac{2^kg_{D-k}}{k!}\times \frac{(-1)^j}{j!} \end{aligned}\]

一次 NTT 即可,复杂度 \(\mathcal O(n\log n)\)

我的实现不是很精细,大概是 \(\mathcal O(n\log P)\) 的。

\(Code:\)

#include<bits/stdc++.h>
using namespace std ;
#define rep( i, s, t ) for( register int i = (s); i <= (t); ++ i )
#define re register
#define int long long
int gi() {
	char cc = getchar() ; int cn = 0, flus = 1 ;
	while( cc < '0' || cc > '9' ) {  if( cc == '-' ) flus = - flus ; cc = getchar() ; }
	while( cc >= '0' && cc <= '9' )  cn = cn * 10 + cc - '0', cc = getchar() ;
	return cn * flus ;
}
const int P = 998244353 ; 
const int Gi = 332748118 ;
const int G = 3 ; 
const int N = 4e5 + 5 ; 
int n, m, D, limit, Inv, L, R[N], f[N], A[N], B[N], f2[N], fac[N], inv[N] ; 
int fpow(int x, int k) {
	int ans = 1, base = x % P ;
	while(k) {
		if(k & 1) ans = 1ll * ans * base % P ;
		base = 1ll * base * base % P, k >>= 1 ;
	} return ans ;
}
void init(int x) {
	limit = 1, L = 0 ; while( limit < x ) limit <<= 1, ++ L ; 
	for(re int i = 0; i < limit; ++ i) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1)) ;
	Inv = fpow( limit, P - 2 ) ; 
}
void NTT(int *a, int type) {
	for(re int i = 0; i < limit; ++ i) if( R[i] > i ) swap( a[i], a[R[i]] ) ;
	for(re int k = 1; k < limit; k <<= 1 ) {
		int d = fpow( (type == 1) ? G : Gi, (P - 1) / (k << 1) ) ;
		for(re int i = 0; i < limit; i += (k << 1))
		for(re int j = i, g = 1; j < i + k; ++ j, g = g * d % P) {
			int nx = a[j], ny = a[j + k] * g % P ;
			a[j] = (nx + ny) % P, a[j + k] = (nx - ny + P) % P ; 
		}
	} if( !type ) rep( i, 0, limit ) a[i] = a[i] * Inv % P ; 
}
int C(int x, int y) {
	if( y > x ) return 0 ; 
	return fac[x] * inv[y] % P * inv[x - y] % P ;  
}
signed main()
{
	D = gi(), n = gi(), m = gi() ; fac[0] = inv[0] = 1 ; 
	m = n - 2 * m ; 
	if( m < 0 ) { puts("0") ; exit(0) ; } 
	rep( i, 1, D ) 
		fac[i] = fac[i - 1] * i % P, 
		inv[i] = fpow( fac[i], P - 2 ) ;
	f2[0] = f[0] = 1 ; 
	rep( i, 1, D ) f[i] = (m & 1) ? P - C(i - 1, m) : C(i - 1, m) ; 
	rep( i, 1, D ) f2[i] = f2[i - 1] * 2 % P ; 
	rep( i, 0, D ) A[i] = f[D - i] * f2[i] % P * inv[i] % P ;
	rep( i, 0, D ) B[i] = (i & 1) ? P - inv[i] : inv[i] ; 
	init(D + D + 5), NTT(A, 1), NTT(B, 1) ;
	rep( i, 0, limit ) A[i] = A[i] * B[i] % P ; 
	NTT(A, 0) ; int ans = 0 ;
	rep( i, 0, D ) f[i] = A[i] * fac[i] % P ; 
	rep( i, 0, D ) ans = (ans + C(D, i) * fpow(2 * i - D + P, n) % P * f[i] % P) % P ; 
	ans = ans * fpow(f2[D], P - 2) % P ;
	cout << ans << endl ; 
	return 0 ;
}

Algorithm3

djq 神仙的解法

同样 \(m\leftarrow n-2m\)

考虑我们要求的其实是:

\[\sum_{k=0}^{m}\binom{D}{k}\Big(\frac{e^{x}-e^{-x}}{2}\Big)^k\Big(\frac{e^x+e^{-x}}{2}\Big)^{D-k}[x^n]\times n! \]

\[\frac{1}{2^D}\sum_{k=0}^{m}\binom{D}{k}(e^{x}-e^{-x})^k(e^x+e^{-x})^{D-k}[x^n]\times n! \]

\(Q_k(x)=\binom{D}{k}(x-1)^k(x+1)^{D-k}\),不难发现答案即 \(\frac{n!}{2^D}\sum_{k=0}^D e^{-Dx}Q_k(e^{2x})[x^n]\)

假设我们知道了 \(Q_k(x)\) 的系数 \(f^{(k)}_{i}\),那么答案即为:

\[2^{-D}\sum_{k}^m\sum_i f^{(k)}_{i}(2i-D)^n \]

于是我们只需要维护 \(Q(x)=\sum_{k=0}^m Q_k(x)\),这样答案即:

\[2^{-D}\sum_i f_i(2i-D)^n \]

注意到:

\[\begin{aligned} &Q(x)=\sum_{k=0}^m Q_k(x) \\&=\sum_{k=0}^m \binom{D}{k}(x-1)^k(x+1)^{D-k} \end{aligned}\]

根据万能并不的求导大法,我们有:

\[\begin{aligned} Q'(x)=\sum_{k=0}^m\binom{D}{k}\bigg(k(x-1)^{k-1}(x+1)^{D-k}+(D-k)(x-1)^k(x+1)^{D-k-1}\bigg) \end{aligned}\]

于是:

\[2D\cdot Q(x)-xQ'(x)= \]

好吧,求导有点考验耐心,我突然不想学习这个解法了。

posted @ 2020-09-26 10:17  Soulist  阅读(133)  评论(0编辑  收藏  举报