題目
Description
Input
Output
Sample Input
2
2 2
Sample Output
18
Data Constraint
思路
先考慮鏈是怎麼做的
預處理f[i][j]表示i個分成j段,段與段之間有序,且乘上的了段的大小,這樣的所有方案權值和。
現在相當於有第i個顏色有b[i]段,把這些合併,是的沒有相鄰兩段顏色相同。
然後容斥
枚舉c[i]第i個顏色實際上是有c[i]段
容斥係數爲(-1)(b[i]-c[i])
劃分數是C(b[i]-1,c[i]-1)
然後把ci卷積一下
考慮環上,使顏色1爲開頭一段,且不爲結尾一段,然後可以旋轉,也就是乘上n/1的段數,發現剛好不會算重。
參考:https://www.cnblogs.com/coldchair/p/12912470.html
代碼
#include<bits/stdc++.h>
using namespace std;
const int P=1000000007;
const int N=55;
const int MAXC=105;
const int L=5005;
int fact[L],invf[L],inv[L],f[L],g[L],g_[L],t[L];
int sum[MAXC][MAXC];
int c[N];
int n,sumc,maxc,ans;
void add(int &x,int y){x=x+y>=P?x+y-P:x+y; }
int sig(int x){return x&1?P-1:1; }
int C(int n,int m){return 1ll*fact[n]*invf[m]%P*invf[n-m]%P; }
int power(int x,int y)
{
int ret=1;
for (; y; y>>=1,x=1ll*x*x%P) if (y&1) ret=1ll*ret*x%P;
return ret;
}
void pre()
{
fact[0]=1;
for (int i=1; i<=sumc; ++i) fact[i]=1ll*fact[i-1]*i%P;
invf[sumc]=power(fact[sumc],P-2);
for (int i=sumc; i>=1; --i) invf[i-1]=1ll*invf[i]*i%P;
for (int i=1; i<=sumc; ++i) inv[i]=1ll*fact[i-1]*invf[i]%P;
sum[0][0]=1;
for (int i=1; i<=maxc; ++i)
for (int j=1; j<=i; ++j)
for (int k=1; k<=i; ++k)
add(sum[i][j],1ll*sum[i-k][j-1]*k%P);
}
int main()
{
freopen("number.in","r",stdin),freopen("number.out","w",stdout);
n=read(),sumc=0;
for (int i=1; i<=n; ++i) sumc+=c[i]=read(),maxc=max(maxc,c[i]);
pre(),f[0]=1;
for (int i=1,curc=0; i<=n; ++i)
{
for (int j=1; j<=c[i]; ++j)
{
t[j]=0;
for (int k=j; k<=c[i]; ++k) add(t[j],1ll*C(k-1,j-1)*sig(k-j)%P*sum[c[i]][k]%P);
}
for (int j=0; j<=curc+c[i]; ++j) g[j]=0;
for (int j=0; j<=curc; ++j)
for (int k=1; k<=c[i]; ++k)
add(g[j+k],1ll*f[j]*t[k]%P*invf[k]%P);
curc+=c[i];
for (int j=0; j<=curc; ++j) swap(f[j],g[j]);
}
ans=0;
for (int j=1; j<=sumc; ++j) add(ans,(1ll*f[j]*fact[j-1]%P-(j>1?1ll*g_[j]*fact[j-2]%P:0)+P)%P);
printf("%d\n",1ll*ans*sumc%P);
fclose(stdin),fclose(stdout);
return 0;
}