Description
有
n
n
n 种颜色,第
i
i
i 种颜色有
c
[
i
]
c[i]
c [ i ] 个。 对于所有
∑
c
[
i
]
\sum c[i]
∑ c [ i ] 个元素的排列,它的贡献为
∏
1
l
k
\prod \frac{1}{l_k}
∏ l k 1 ,其中
l
k
l_k
l k 为首尾相接之后第
k
k
k 个极大连续段的长度。 求
(
∑
c
[
i
]
)
!
∏
c
[
i
]
!
\frac{(\sum c[i])!}{\prod c[i]!}
∏ c [ i ] ! ( ∑ c [ i ] ) ! 个排列的贡献之和模998244353。
n
≤
1
e
5
,
∑
c
[
i
]
≤
2
e
5
n\leq1e5,\sum c[i]\leq2e5
n ≤ 1 e 5 , ∑ c [ i ] ≤ 2 e 5
Solution
这是一道容斥容斥再容斥的题目。 首先考虑一条链,单独考虑一个颜色的生成函数的贡献,那么这个颜色分成
j
j
j 段的贡献就是(有
e
x
k
=
∑
i
>
=
0
(
x
k
)
i
i
!
e^{xk}=\sum_{i>=0}\frac{(xk)^i}{i!}
e x k = ∑ i > = 0 i ! ( x k ) i ):
(
e
x
−
1
)
j
[
x
c
[
i
]
]
=
∑
k
=
0
j
(
j
k
)
(
−
1
)
k
−
j
k
c
[
i
]
c
[
i
]
!
(e^x-1)^j[x^{c[i]}]=\frac{\sum_{k=0}^j(_j^k)(-1)^{k-j}k^{c[i]}}{c[i]!}
( e x − 1 ) j [ x c [ i ] ] = c [ i ] ! ∑ k = 0 j ( j k ) ( − 1 ) k − j k c [ i ] 这样就可以卷积求出所有
j
j
j 的贡献。 考虑直接把同一种颜色的
j
j
j 种元素当做可重元素,那么就是可重元素的排列问题,系数乘上
1
j
!
\frac{1}{j!}
j ! 1 即可卷积。但是这样可能两个同一种颜色的块分到了相邻的地方,所以要再容斥。 暴力枚举有
k
k
k 个合并到了一起。
g
k
=
∑
k
=
0
j
−
1
(
j
−
1
k
)
(
−
1
)
k
f
j
g_k=\sum_{k=0}^{j-1}(_{j-1}^k)(-1)^{k}f_j
g k = ∑ k = 0 j − 1 ( j − 1 k ) ( − 1 ) k f j 。用
g
k
g_k
g k 求可重元素排列的方案数。
接下来考虑有环的答案,直接考虑第一个是哪个元素,以及这个元素有多少个,那么贡献就要再乘上这个个数。 同样考虑如果第一段的贡献特殊,颜色
i
i
i 有
j
+
1
j+1
j + 1 段的贡献:
e
x
x
(
e
x
−
1
)
j
[
x
c
[
i
]
]
=
∑
k
=
0
j
(
j
k
)
(
−
1
)
j
−
k
(
k
+
1
)
c
[
i
]
−
1
(
c
[
i
]
−
1
)
!
e^xx(e^x-1)^j[x^{c[i]}]=\frac{\sum_{k=0}^j(_j^k)(-1)^{j-k}(k+1)^{c[i]-1}}{(c[i]-1)!}
e x x ( e x − 1 ) j [ x c [ i ] ] = ( c [ i ] − 1 ) ! ∑ k = 0 j ( j k ) ( − 1 ) j − k ( k + 1 ) c [ i ] − 1 但是不能有一段放在组合之后的第一段和最后一段,所以我们要在之前可重排列的容斥的基础之上再容斥,即钦定有一段在第一段,有一段在最后一段,在原方案上减去它们再加上有一段在第一段同时有一段在最后一段。
考虑第一部分是没有开头的生成函数,第二部分是有的,分别记为
F
,
G
F,G
F , G ,那么用合并果子的方式合并不同的颜色,
G
=
F
1
∗
G
2
+
G
1
∗
F
2
,
F
=
F
1
∗
F
2
G=F_1*G_2+G_1*F_2,F=F_1*F_2
G = F 1 ∗ G 2 + G 1 ∗ F 2 , F = F 1 ∗ F 2 。 总复杂度
O
(
n
l
o
g
2
n
)
O(n\ log^2\ n)
O ( n l o g 2 n )
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
#define ll long long
#define mo 998244353
#define maxn 200005
#define maxm 525000
#define N 524288
#define clear(a) memset(a,0,sizeof(a))
#define I(x) (((x)&1)?-1:1)
using namespace std;
int n, i, j, k, c[ maxn] ;
ll f[ maxm] , g[ maxm] , fct[ maxn] , invf[ maxn] ;
void read ( int & x) {
x= 0 ; char ch= getchar ( ) ;
for ( ; ch< '0' || ch> '9' ; ch= getchar ( ) ) ;
for ( ; ch>= '0' && ch<= '9' ; ch= getchar ( ) ) x= x* 10 + ch- '0' ;
}
ll ksm ( ll x, ll y) {
ll s= 1 ;
for ( ; y; y/ = 2 , x= x* x% mo) if ( y& 1 )
s= s* x% mo;
return s;
}
ll C ( int n, int m) {
return fct[ n] * invf[ n- m] % mo* invf[ m] % mo;
}
int lim, bt[ maxm] ; ll A[ maxm] , B[ maxm] , w[ maxm] ;
int getlim ( int x) {
int lim= 1 ; while ( lim<= x) lim<<= 1 ;
for ( int i= 1 ; i< lim; i++ ) bt[ i] = ( bt[ i>> 1 ] >> 1 ) | ( ( i& 1 ) * ( lim>> 1 ) ) ;
return lim;
}
void dft ( ll * a, int sig) {
for ( int i= 0 ; i< lim; i++ ) if ( i< bt[ i] ) swap ( a[ i] , a[ bt[ i] ] ) ;
for ( int mid= 1 ; mid< lim; mid<<= 1 ) {
int d= sig* N/ ( mid<< 1 ) , s= ( sig< 0 ) ? N: 0 ;
for ( int j= 0 ; j< lim; j+ = mid<< 1 ) {
for ( int k= 0 , p= s; k< mid; k++ , p+ = d) {
ll x= a[ j+ k] , y= a[ j+ k+ mid] * w[ p] ;
a[ j+ k] = ( x+ y) % mo, a[ j+ k+ mid] = ( x- y) % mo;
}
}
}
if ( sig< 0 ) {
ll inv= ksm ( lim, mo- 2 ) ;
for ( int i= 0 ; i< lim; i++ ) a[ i] = a[ i] * inv% mo;
}
}
void multi ( ll * a, ll * b) {
dft ( a, 1 ) , dft ( b, 1 ) ;
for ( int i= 0 ; i< lim; i++ ) b[ i] = a[ i] * b[ i] % mo;
dft ( b, - 1 ) ;
}
int tot;
vector< ll> F[ maxn] , G[ maxn] ;
ll f1[ maxm] , g1[ maxm] , f2[ maxm] , g2[ maxm] , f0[ maxm] , g0[ maxm] ;
struct arr{ int i, s; arr ( int _i= 0 , int _s= 0 ) { i= _i, s= _s; } } ;
int operator < ( arr a, arr b) { return a. s> b. s; }
priority_queue< arr> Q;
int main ( ) {
freopen ( "always.in" , "r" , stdin ) ;
freopen ( "always.out" , "w" , stdout ) ;
fct[ 0 ] = 1 ; for ( i= 1 ; i< maxn; i++ ) fct[ i] = fct[ i- 1 ] * i% mo;
invf[ maxn- 1 ] = ksm ( fct[ maxn- 1 ] , mo- 2 ) ;
for ( i= maxn- 2 ; i>= 0 ; i-- ) invf[ i] = invf[ i+ 1 ] * ( i+ 1 ) % mo;
w[ 0 ] = 1 , w[ 1 ] = ksm ( 3 , ( mo- 1 ) / N) ;
for ( i= 2 ; i<= N; i++ ) w[ i] = w[ i- 1 ] * w[ 1 ] % mo;
read ( n) ;
for ( i= 1 ; i<= n; i++ ) read ( c[ i] ) ;
if ( n== 1 ) { printf ( "%lld" , invf[ c[ 1 ] ] ) ; return 0 ; }
for ( int t= 1 ; t<= n; t++ ) {
int m= c[ t] ;
lim= getlim ( 2 * m) ;
memset ( A, 0 , sizeof ( ll) * lim) ;
memset ( B, 0 , sizeof ( ll) * lim) ;
for ( i= 0 ; i<= m; i++ )
A[ i] = invf[ i] * ksm ( i, m) % mo, B[ i] = invf[ i] * I ( i) * invf[ m] % mo;
multi ( A, B) ;
for ( i= 1 ; i<= m; i++ ) f[ i] = B[ i] * fct[ i] % mo;
memset ( A, 0 , sizeof ( ll) * lim) ;
memset ( B, 0 , sizeof ( ll) * lim) ;
for ( i= 1 ; i<= m; i++ ) A[ i] = f[ i] * fct[ i- 1 ] % mo;
for ( i= 0 ; i<= m; i++ ) B[ m- i] = invf[ i] * I ( i) ;
multi ( A, B) ;
for ( i= 1 ; i<= m; i++ ) g[ i] = B[ m+ i] * invf[ i- 1 ] % mo;
F[ t] . push_back ( 0 ) ;
for ( i= 1 ; i<= m; i++ ) F[ t] . push_back ( g[ i] * invf[ i] % mo) ;
memset ( A, 0 , sizeof ( ll) * lim) ;
memset ( B, 0 , sizeof ( ll) * lim) ;
for ( i= 0 ; i< m; i++ )
A[ i] = invf[ i] * ksm ( i+ 1 , m- 1 ) % mo, B[ i] = invf[ i] * I ( i) * invf[ m- 1 ] % mo;
multi ( A, B) ;
for ( i= 0 ; i< m; i++ ) f[ i] = B[ i] * fct[ i] % mo; f[ m] = 0 ;
memset ( A, 0 , sizeof ( ll) * lim) ;
memset ( B, 0 , sizeof ( ll) * lim) ;
for ( i= 1 ; i< m; i++ ) A[ i] = fct[ i- 1 ] * f[ i] % mo;
for ( i= 0 ; i<= m; i++ ) B[ m- i] = invf[ i] * I ( i) ;
multi ( A, B) ;
g[ m+ 1 ] = g[ m+ 2 ] = 0 ;
for ( g[ 0 ] = f[ 0 ] , i= 1 ; i<= m; i++ )
g[ i] = B[ m+ i] * invf[ i- 1 ] % mo;
for ( i= 0 ; i<= m; i++ ) g[ i] = ( g[ i] - 2 * g[ i+ 1 ] + g[ i+ 2 ] ) % mo;
for ( i= 0 ; i<= m; i++ ) G[ t] . push_back ( g[ i] * invf[ i] % mo) ;
Q. push ( arr ( t, m) ) ;
}
tot= n;
while ( Q. size ( ) > 1 ) {
arr t1= Q. top ( ) ; Q. pop ( ) ;
arr t2= Q. top ( ) ; Q. pop ( ) ;
lim= getlim ( t1. s+ t2. s) ;
memset ( f1, 0 , sizeof ( ll) * lim) ;
memset ( g1, 0 , sizeof ( ll) * lim) ;
memset ( f2, 0 , sizeof ( ll) * lim) ;
memset ( g2, 0 , sizeof ( ll) * lim) ;
for ( i= 0 ; i< F[ t1. i] . size ( ) ; i++ ) f1[ i] = F[ t1. i] [ i] ;
for ( i= 0 ; i< G[ t1. i] . size ( ) ; i++ ) g1[ i] = G[ t1. i] [ i] ;
for ( i= 0 ; i< F[ t2. i] . size ( ) ; i++ ) f2[ i] = F[ t2. i] [ i] ;
for ( i= 0 ; i< G[ t2. i] . size ( ) ; i++ ) g2[ i] = G[ t2. i] [ i] ;
memset ( f0, 0 , sizeof ( ll) * lim) ;
memset ( g0, 0 , sizeof ( ll) * lim) ;
dft ( f1, 1 ) , dft ( g1, 1 ) , dft ( f2, 1 ) , dft ( g2, 1 ) ;
for ( i= 0 ; i< lim; i++ ) {
g0[ i] = ( f1[ i] * g2[ i] % mo+ g1[ i] * f2[ i] % mo) % mo;
f0[ i] = f1[ i] * f2[ i] % mo;
}
dft ( g0, - 1 ) , dft ( f0, - 1 ) ;
k= t1. s+ t2. s;
for ( i= 0 ; i<= t2. s; i++ )
F[ t2. i] [ i] = f0[ i] , G[ t2. i] [ i] = g0[ i] ;
for ( i= t2. s+ 1 ; i<= k; i++ ) {
F[ t2. i] . push_back ( f0[ i] ) ;
G[ t2. i] . push_back ( g0[ i] ) ;
}
Q. push ( arr ( t2. i, k) ) ;
}
ll ans= 0 ; arr t= Q. top ( ) ;
for ( i= 0 ; i< G[ t. i] . size ( ) ; i++ )
( ans+ = G[ t. i] [ i] * fct[ i] % mo) % = mo;
printf ( "%lld" , ( ans+ mo) % mo) ;
}