题意
给定 种颜色的球,第 种颜色的球数量为 个,一种排列的贡献可以如下计算:先把这个序列首尾相连,然后把所有相邻且颜色相同的段拿出来,贡献为他们的长度之积,求所有排列的贡献和,原排列不同,首尾相连后相同的排列不算同一种。模 。
先考虑一个序列怎么做
我们对每一个
枚举将
分成
段,算出这种情况下的方案数已经每一种颜色的贡献
那么答案可以表示为(用
表示把
分成
段的所有情况的系数之和)
发现
就是把
分成
块然后每一块选一个的方案数,巧妙地发现
考虑求
,把所有颜色放在一起容斥,枚举强制合并的端点个数
那么放到一起就是,换成枚举合并之后的段数
发现后面有一个
,考虑构造每一种颜色的
后面的一坨可以
求,然后分治
就可以全部乘起来
考虑环的情况怎么做
强制以 1 开头,那么 1 的生成函数的
会变成
减去强制以 1 开头,以 1 结尾的个数,这个的
会变成
但发现还是不对,如果环的循环是
的话,我们需要统计
遍,而实际上只统计了
遍,我们将第一个生成函数中含
的项除一个
,最后乘上
就可以了
#include<bits/stdc++.h>
#define cs const
using namespace std;
cs int N = 2e5 + 5;
int read(){
int cnt = 0, f = 1; char ch = 0;
while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1; }
while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
return cnt * f;
}
#define poly vector<int>
#define pb push_back
cs int Mod = 998244353;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
void Add(int &a, int b){ a = add(a, b); }
void Dec(int &a, int b){ a = dec(a, b); }
void Mul(int &a, int b){ a = mul(a, b); }
int coe(int a){ return (a&1)?Mod-1:1; }
int ksm(int a, int b){ int ans=1; for(;b;b>>=1,a=mul(a,a)) if(b&1) ans=mul(ans,a); return ans; }
int n, m, a[N];
int fac[N], ifac[N], inv[N];
poly f[N];
int C(int n, int m){ if(n<0||m<0||n<m) return 0; return mul(fac[n],mul(ifac[n-m],ifac[m])); }
void Fac_init(int n){
fac[0]=fac[1]=ifac[0]=ifac[1]=inv[0]=inv[1]=1;
for(int i=2; i<=n; i++) inv[i]=mul(Mod-Mod/i,inv[Mod%i]);
for(int i=2; i<=n; i++) fac[i]=mul(fac[i-1],i), ifac[i]=mul(ifac[i-1],inv[i]);
}
cs int K = 18;
poly w[K+1];
poly rev; int up, bit;
void init(int deg){
up=1,bit=0; while(up<deg) up<<=1,++bit; rev.resize(up);
for(int i=0; i<up; i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
}
void NTT_init(){
for(int i=1; i<=K; i++) w[i].resize(1<<i-1);
int wn=ksm(3,(Mod-1)/(1<<K)); w[K][0] = 1;
for(int i = 1; i < (1<<K-1); i++) w[K][i]=mul(w[K][i-1], wn);
for(int i = K-1; i; i--) for(int j=0; j<(1<<i-1); j++) w[i][j]=w[i+1][j<<1];
}
void NTT(poly &a, int typ){
for(int i=0; i<up; i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
for(int i=1,l=1; i<up; i<<=1,++l)
for(int j=0; j<up; j+=(i<<1))
for(int k=0; k<i; k++){
int x=a[k+j], y=mul(a[k+j+i],w[l][k]);
a[k+j]=add(x,y); a[k+j+i]=dec(x,y);
}
if(typ==-1){
reverse(a.begin()+1,a.end());
for(int iv=ksm(up,Mod-2),i=0; i<up; i++) a[i]=mul(a[i],iv);
}
}
poly operator * (poly a, poly b){
int deg = a.size()+b.size()-1;
init(deg); a.resize(up); b.resize(up); NTT(a,1); NTT(b,1);
for(int i=0; i<up; i++) a[i]=mul(a[i],b[i]); NTT(a,-1);
a.resize(deg); return a;
}
poly Solve(int l, int r){
if(l==r){ for(int i=1; i<f[l].size(); i++) Mul(f[l][i], ifac[i]); return f[l]; }
int mid=(l+r)>>1; return Solve(l,mid) * Solve(mid+1,r);
}
int main(){
n = read();
for(int i = 1; i <= n; i++) m+=a[i]=read();
Fac_init(m); NTT_init();
for(int i = 1; i <= n; i++){
poly g(a[i]+1, 0), h(a[i]+1, 0);
for(int j = 1; j <= a[i]; j++) g[j]=mul(fac[j-1], C(a[i]+j-1,a[i]-j));
if(i==1) for(int j=1; j<=a[i]; j++) Mul(g[j], inv[j]);
for(int j=0; j<=a[i]; j++) h[a[i]-j] = mul(ifac[j], coe(j));
g=g*h; f[i].resize(a[i]+1);
for(int j=1; j<=a[i]; j++) f[i][j]=mul(g[a[i]+j], ifac[j-1]);
}
poly F=Solve(2,n);
poly G(a[1],0);
for(int i=0; i<G.size(); i++) G[i]=mul(f[1][i+1], ifac[i]);
G=G*F;
int ans=0;
for(int i=1; i<G.size(); i++) Add(ans, mul(G[i],fac[i]));
if(a[1]>1){
G=poly(a[1]-1,0);
for(int i=0; i<G.size(); i++) G[i]=mul(f[1][i+2], ifac[i]);
G=G*F;
for(int i=1; i<G.size(); i++) Dec(ans, mul(G[i],fac[i]));
} cout << mul(ans, m); return 0;
}