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} ∏lk1,其中 l k l_k lk为首尾相接之后第 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≤1e5,∑c[i]≤2e5
Solution
- 这是一道容斥容斥再容斥的题目。
- 首先考虑一条链,单独考虑一个颜色的生成函数的贡献,那么这个颜色分成 j j j段的贡献就是(有 e x k = ∑ i > = 0 ( x k ) i i ! e^{xk}=\sum_{i>=0}\frac{(xk)^i}{i!} exk=∑i>=0i!(xk)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]!} (ex−1)j[xc[i]]=c[i]!∑k=0j(jk)(−1)k−jkc[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 gk=∑k=0j−1(j−1k)(−1)kfj。用 g k g_k gk求可重元素排列的方案数。
- 接下来考虑有环的答案,直接考虑第一个是哪个元素,以及这个元素有多少个,那么贡献就要再乘上这个个数。
- 同样考虑如果第一段的贡献特殊,颜色 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)!} exx(ex−1)j[xc[i]]=(c[i]−1)!∑k=0j(jk)(−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=F1∗G2+G1∗F2,F=F1∗F2。
- 总复杂度 O ( n l o g 2 n ) O(n\ log^2\ n) O(n log2 n)
#include
#include
#include
#include
#include
#include
#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);
}