关原幽
takanashi_mifuru · · 题解
首先给颜色打标签,最后撕掉就好了。
首先考虑想直接枚举
然后就是这个题最鬼的一步,考虑这样的话因为分段需要枚举十分不优,我们需要想个听上去有道理的办法将贡献分开。
那么考虑对于一个大小为
用乘法分配律把他拆开就变成了对于每个点
假设我们知道有
但是这个还是很难求,我们考虑环外点的权值是固定的,而环内点的权值却并非,我们考虑再乘法分配律一下,将环拆为若干单调的链,因为链单调所以链中非链头的点附加值确定存在,而链头附加值存不存在都无所谓干脆因为使用的是本来的权值所以没问题。
然后问题就是如何把链拼起来,容易发现这就是第一类斯特林数的定义,一步一步代回去便能得到答案。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int P=998244353;
int power(int x,int y=P-2){
if(!y)return 1;
int tmp=power(x,y>>1);
if(y&1)return tmp*tmp%P*x%P;
return tmp*tmp%P;
}
int n;
int A[5005];
int fac[5005];
int invfac[5005];
int S1[5005][5005];
int S2[5005][5005];
int C(int n,int m){
return fac[n]*invfac[m]%P*invfac[n-m]%P;
}
int dp[5005][5005];
int h[5005];
int g[5005];
int f[5005];
int ans[5005];
int SUM;
int mul=1;
signed main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&A[i]);
SUM+=A[i];
if(SUM>=P)SUM-=P;
}
sort(A+1,A+1+n);
fac[0]=1;
for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%P;
invfac[n]=power(fac[n]);
for(int i=n;i>=1;i--)invfac[i-1]=invfac[i]*i%P;
int num=1;
for(int i=2;i<=n;i++){
if(A[i] xor A[i-1]){
mul=mul*invfac[num]%P;
num=0;
}
num++;
}
mul=mul*invfac[num]%P;
S2[0][0]=1;
for(int i=1;i<=n;i++){
for(int k=1;k<=i;k++){
S2[i][k]=S2[i-1][k-1]+k*S2[i-1][k];
S2[i][k]%=P;
}
}
S1[0][0]=1;
for(int i=1;i<=n;i++){
for(int k=1;k<=i;k++){
S1[i][k]=S1[i-1][k]*(i-1)+S1[i-1][k-1];
S1[i][k]%=P;
}
}
dp[0][0]=1;
for(int i=1;i<=n;i++){
for(int j=0;j<=i;j++){
dp[i][j]=dp[i-1][j]*(i+SUM)+dp[i-1][j]*(-1)*j;
if(j)dp[i][j]+=dp[i-1][j-1]*(A[i]+1);
dp[i][j]=(dp[i][j]%P+P)%P;
}
}
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
h[i]+=dp[n][j]*S1[j][i];
h[i]%=P;
}
}
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){//
int f=1;
if((j-i)&1)f=-1;
g[i]+=h[j]*f*C(j,i);
g[i]=(g[i]%P+P)%P;
}
}
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
f[i]+=g[j]*S2[j][i];
// if(i==2){
// printf("%lld*%lld\n",g[j],S2[j][i]);
// }
f[i]%=P;
}
}
// printf("%lld %lld\n",f[1],f[2]);
for(int i=1;i<=n;i++)f[i]=f[i]*fac[i]%P;
// f[2]=12;
// f[1]=12,f[2]=8;
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){//
int fl=1;
if((j-i)&1)fl=-1;
ans[i]+=fl*f[j]*C(j-1,i-1);
ans[i]=(ans[i]%P+P)%P;
}
}
for(int i=1;i<=n;i++){
printf("%lld\n",ans[i]*mul%P);
}
// puts("");
return 0;
}//