「ABC215G」Colorful Candies 2

题目

点这里看题目。

分析

介绍两种做法,一种是简单的题解方法,另一种是复杂的做法。

题解

假设有 (C) 种不同的颜色,我们可以先将颜色离散化,标号为 (1,2,dots,C)。设第 (i) 种颜色数量为 (a_i)

“不同的颜色的数量”也就是出现了的颜色的种数。因此我们可以设离散随机变量 (X_i) 表示第 (i) 种颜色是否出现,如果 (X_i=1) 则第 (i) 种颜色出现,否则 (X_i=0),表示第 (i) 种颜色不出现。

我们需要求的是 (E[sum_{i=1}^CX_i]=sum_{i=1}^CE[X_i]),而由于 (X_i) 的取值只有 ({0,1}),所以 (E[X_i]=P(X_i=1))。我们也就是要求第 (i) 种颜色出现的概率,当我们枚举选择的糖果数量 (k) 时,使用容斥原理得到概率为:

[frac{inom{n}{k}-inom{n-a_i}{k}}{inom{n}{k}} ]

(n,k) 确定时,这个式子只和 (a_i) 相关。由于 (sum_{i=1}^Ca_i=n),所以不同的 (a_i) 只有 $ O(sqrt n)$ 种。对于不同的 (a_i) 单独计算,乘上系数即可。复杂度为 (O(nsqrt n))

复杂做法

显然将颜色排序不会影响结果,我们将输入的 (c) 序列排序,那么对于选出来的 (k) 个糖果,只有可能在相邻的两项之间产生贡献。根据期望的线性性,我们可以枚举相邻的两项,计算它们可能带来的贡献。

枚举 (k,k>1),可以计算所有的贡献为:

[inom{n}{k}+sum_{i=1}^{n-1}sum_{j=i+1}^n[c_i ot=c_j]inom{n-j+i-1}{k-2} ]

期望就还需要除掉 (inom{n}{k}) 的情况总数,下面仅对这个式子化简。

([c_i ot=c_j]) 不好搞,把它拆成 (1-[c_i=c_j])。我们先处理前面一半:

[egin{aligned} sum_{i=1}^{n-1}sum_{j=i+1}^ninom{n-j+i-1}{k-2} &=sum_{i=1}^{n-1}inom{n-1-i}{k-2}(n-i)\ &=sum_{i=1}^{n-1}inom{n-i}{k-1}(k-1)\ &=(k-1)left(inom{n}{k}-inom{0}{k-1} ight)\ &=(k-1)inom{n}{k} end{aligned} ]

接着考虑 ([c_i=c_j])。假设 (c_i) 出现次数为 (q),这就相当于要求 (1le j-ile q),所以:

[egin{aligned} sum_{j=1}^{q-1}inom{n-1-j}{k-2}(q-j) &=sum_{j=1}^{q-1}sum_{i=0}^{k-2}inom{n-q}{k-2-i}inom{q-1-j}{i}(q-j)\ &=sum_{i=0}^{k-2}inom{n-q}{k-2-i}sum_{j=1}^{q-1}inom{q-j}{i+1}(i+1)\ &=sum_{i=0}^{k-2}inom{n-q}{k-2-i}inom{q}{i+2}(i+1)\ &=sum_{i=1}^{k}inom{n-q}{i}inom{q}{i+2}(i-1) end{aligned} ]

现在开始,式子看起来不太友好,我们改用生成函数。尝试构造 (sum_{ige 1}inom{q}{i}(i-1)x^i),从系数入手:

[egin{aligned} sum_{ige 1}inom{q}{i}(i-1)x^i &=left(frac{(1+x)^q-1}{x} ight)'x^2\ &=q(1+x)^{q-1}x-(1+x)^q+1 end{aligned} ]

对于系数的构造恰好使得我们得到的生成函数没有常数项。所以和式正好是卷积的形式,我们需要的答案为:

[[x^k]q(1+x)^{n-1}x-(1+x)^n+(1+x)^{n-q} ]

同样的道理,不同的 (q) 只有 (O(sqrt{n})) 种,所以对于不同的 (q) 计算一遍即可。复杂度为 (O(nsqrt{n}))

小结:

  1. 比较一下两种做法,第一种做法简单的原因在于它将每种颜色单独考虑,而不像第二种是考虑一对糖果,所以才能大大简化运算;当然,第二种方法其实也用了这种思想。
  2. 推导生成函数的时候,以系数为突破口,常用的方法之一就是根据已有结果构造出需要的系数。
  3. 再次提醒用到的 (sqrt n) 性质

代码

这里只给出第二种做法的代码:

#include <cstdio>
#include <vector>
#include <utility>
#include <algorithm>
 
#define rep( i, a, b ) for( int i = (a) ; i <= (b) ; i ++ )
#define per( i, a, b ) for( int i = (a) ; i >= (b) ; i -- )
 
const int mod = 998244353;
const int MAXN = 1e5 + 5;
 
template<typename _T>
void read( _T &x )/*{{{*/
{
	x = 0; char s = getchar(); int f = 1;
	while( ! ( '0' <= s && s <= '9' ) ) { f = 1; if( s == '-' ) f = -1; s = getchar(); }
	while( '0' <= s && s <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar(); }
	x *= f;
}/*}}}*/
 
template<typename _T>
void write( _T x )/*{{{*/
{
	if( x < 0 ) putchar( '-' ), x = -x;
	if( 9 < x ) write( x / 10 );
	putchar( x % 10 + '0' );
}/*}}}*/

typedef std :: pair<int, int> Occurence;

std :: vector<Occurence> occ;

int fac[MAXN], ifac[MAXN];
int c[MAXN], app[MAXN];
int N;
 
inline int Qkpow( int, int );
inline int Mul( int x, int v ) { return 1ll * x * v % mod; }
inline int Inv( const int a ) { return Qkpow( a, mod - 2 ); }
inline int Sub( int x, int v ) { return ( x -= v ) < 0 ? x + mod : x; }
inline int Add( int x, int v ) { return ( x += v ) >= mod ? x - mod : x; }
inline int C( int n, int m ) { return n < m ? 0 : Mul( fac[n], Mul( ifac[m], ifac[n - m] ) ); }
 
inline int Qkpow( int base, int indx )/*{{{*/
{
	int ret = 1;
	while( indx )
	{
		if( indx & 1 ) ret = Mul( ret, base );
		base = Mul( base, base ), indx >>= 1;
	}
	return ret;
}/*}}}*/
 
void Init( const int n )/*{{{*/
{
	fac[0] = 1; rep( i, 1, n ) fac[i] = Mul( fac[i - 1], i );
	ifac[n] = Inv( fac[n] ); per( i, n - 1, 0 ) ifac[i] = Mul( ifac[i + 1], i + 1 );
}/*}}}*/
 
int main()
{
	read( N ), Init( N );
	rep( i, 1, N ) read( c[i] );
	std :: sort( c + 1, c + 1 + N );
	for( int i = 1, j ; i <= N ; i = j )
	{
		for( j = i ; j <= N && c[j] == c[i] ; j ++ );
		app[j - i] ++;
	}
	rep( i, 1, N ) if( app[i] )
		occ.push_back( std :: make_pair( i, app[i] ) );
	puts( "1" );
	rep( k, 2, N )
	{
		int ans = Mul( k - 1, C( N, k ) );
		for( int i = 0 ; i < ( int ) occ.size() ; i ++ )
		{
			int q = occ[i].first;
			int res = 0;
			res = Add( res, Mul( C( N - 1, k - 1 ), q ) );
			res = Sub( res, C( N, k ) );
			res = Add( res, C( N - q, k ) );
			ans = Sub( ans, Mul( res, occ[i].second ) );
		}
		write( Add( 1, Mul( ans, Inv( C( N, k ) ) ) ) ), putchar( '
' );
	}
	return 0;
}
原文地址:https://www.cnblogs.com/crashed/p/15177438.html