注意到如果可以不联通的话方案数为
2
(
n
−
1
2
)
2^{\binom{n-1}{2}}
2(2n−1) 种,即考虑前面随便连边,最后一个点存在唯一一种合法的连边方式,最后
l
n
ln
ln 或分治
n
t
t
ntt
ntt 或
n
2
n^2
n2 容斥回去即可
#include<bits/stdc++.h>
#define cs const
#define pb push_back
#define poly vector<int>
using namespace std;
cs int Mod =1e9+7;
int add(int a, int b){return a + b >= Mod ? a + b - Mod : a + b;}
int dec(int a, int b){return a - b <0? a - b + Mod : a - b;}
int mul(int a, int b){return1ll * a * b % Mod;}
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 ksm(int a, int b){ int as=1;for(;b;b>>=1,Mul(a,a))if(b&1)Mul(as,a);return as;}
cs int N =2e3+50;
int n, f[2][N], fc[N], ifc[N];
int C(int n, int m){if(n<0||m<0||n<m)return0;returnmul(fc[n],mul(ifc[n-m],ifc[m]));}
void fc_init(int n){
fc[0]=fc[1]=ifc[0]=ifc[1]=1;for(int i=2; i<=n; i++) fc[i]=mul(fc[i-1],i);
ifc[n]=ksm(fc[n],Mod-2);for(int i=n-1; i>=2; i--) ifc[i]=mul(ifc[i+1],i+1);}
int main(){
#ifdef FSYolanda
freopen("road.in","r",stdin);freopen("road.out","w",stdout);
#endif
scanf("%d",&n);fc_init(n); poly F(n+1,0);for(int i=1; i<=n; i++) F[i]=ksm(2,(i-1)*(i-2)>>1);
poly G = F;for(int i=1; i<=n; i++){for(int j=1; j<i; j++)Dec(F[i],mul(C(i-1,j-1),mul(F[j],G[i-j])));} cout<<mul(F[n],n*(n-1)>>1);}
看成一个长为
m
m
m 的序列,每种颜色的球为
a
i
a_i
ai 个,带标号,强制标号为 1 的在最前方(除掉第一个放的),那么答案就是合法的排列数 若不考虑第一个不除,答案即为
m
!
∏
a
i
\frac{m!}{\prod a_i}
∏aim! 下面考虑第一个,首先第一个出现位置在其它球的第一个后方,我们对这个进行容斥,考虑点一个集合
S
S
S 在当前枚举的
t
t
t 后方,那么
t
t
t 的贡献是
(
−
1
)
∣
S
∣
a
t
!
(
∑
i
∈
S
a
i
+
a
t
−
1
a
t
−
1
)
∗
(
∑
i
∈
S
a
i
)
!
∏
i
∈
S
a
i
∗
(
m
∑
i
∈
S
a
i
+
a
t
)
∗
(
∑
i
∉
S
,
i
≠
t
a
i
)
!
∏
i
∉
S
,
i
≠
t
a
i
=
(
−
1
)
∣
S
∣
a
t
2
∏
i
a
i
(
∑
i
∈
S
a
i
+
a
t
−
1
)
!
m
!
(
m
−
∑
i
∈
S
a
i
−
a
t
)
!
(
∑
i
∈
S
a
i
+
a
t
)
!
(
∑
i
∉
S
,
i
≠
t
a
i
)
!
=
m
!
∑
S
(
−
1
)
∣
S
∣
a
t
2
∏
a
i
1
∑
i
∈
S
a
i
+
a
t
(-1)^{|S|}a_t!\binom{\sum_{i\in S}a_i+a_t-1}{a_t-1}*\frac{(\sum_{i\in S}a_i)!}{\prod_{i\in S}a_i}*\binom{m}{\sum_{i\in S}a_i+a_t}*\frac{(\sum_{i\notin S,i\neq t}a_i)!}{\prod_{i\notin S,i\neq t} a_i}\\ =(-1)^{|S|}\frac{a_t^2}{\prod_i a_i}(\sum_{i\in S}a_i+a_t-1)!\frac{m!}{(m-\sum_{i\in S}a_i-a_t)!(\sum_{i\in S}a_i+a_t)!}(\sum_{i\notin S,i\neq t}a_i)!\\=m!\sum_S(-1)^{|S|}\frac{a_t^2}{\prod a_i}\frac{1}{\sum_{i\in S}a_i+a_t}
(−1)∣S∣at!(at−1∑i∈Sai+at−1)∗∏i∈Sai(∑i∈Sai)!∗(∑i∈Sai+atm)∗∏i∈/S,i=tai(∑i∈/S,i=tai)!=(−1)∣S∣∏iaiat2(i∈S∑ai+at−1)!(m−∑i∈Sai−at)!(∑i∈Sai+at)!m!(i∈/S,i=t∑ai)!=m!S∑(−1)∣S∣∏aiat2∑i∈Sai+at1 那么我们只需要
d
p
dp
dp 出
f
T
=
∑
∑
i
∈
S
a
i
=
T
,
t
∉
S
(
−
1
)
∣
S
∣
f_T=\sum_{\sum_{i\in S}a_i=T,t\notin S}(-1)^{|S|}
fT=∑i∈Sai=T,t∈/S∑(−1)∣S∣ 对于限制可以回退一下背包,
O
(
n
m
)
O(nm)
O(nm),在膜拜了大神
l
d
x
ldx
ldx 之后即可分治
n
t
t
ntt
ntt 做到
O
(
m
log
2
m
)
O(m\log^2m)
O(mlog2m)
#include<bits/stdc++.h>
#define cs const
#define pb push_back
#define poly vector<int>
using namespace std;
cs int Mod =1e9+7;
int add(int a, int b){return a + b >= Mod ? a + b - Mod : a + b;}
int dec(int a, int b){return a - b <0? a - b + Mod : a - b;}
int mul(int a, int b){return1ll * a * b % Mod;}
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 ksm(int a, int b){ int as=1;for(;b;b>>=1,Mul(a,a))if(b&1)Mul(as,a);return as;}
cs int N =55, M =1e3+50;
int n, m, a[N], iv[M], fc[M], ifc[M];
int dp[M];
void fc_init(int n){
fc[0]=fc[1]=ifc[0]=ifc[1]=iv[0]=iv[1]=1;for(int i=2; i<=n; i++) iv[i]=mul(Mod-Mod/i,iv[Mod%i]);for(int i=2; i<=n; i++) fc[i]=mul(fc[i-1],i);
ifc[n]=ksm(fc[n],Mod-2);for(int i=n-1; i>=2; i--) ifc[i]=mul(ifc[i+1],i+1);}
int main(){
#ifdef FSYolanda
freopen("1.in","r",stdin);// freopen("comb.out","w",stdout);
#endif
scanf("%d",&n); int mt=1;for(int i=1; i<=n; i++)scanf("%d",&a[i]), m+=a[i],Mul(mt,a[i]);fc_init(m); mt=ksm(mt,Mod-2);Mul(mt,fc[m]); dp[0]=1;for(int i=1,S=0; i<=n; i++){
S+=a[i];for(int j=S; j>=a[i]; j--)Dec(dp[j],dp[j-a[i]]);} int ans =0;for(int i=1; i<=n; i++){for(int j=a[i]; j<=m; j++)Add(dp[j],dp[j-a[i]]); int Sum=0;for(int j=0; j<=m; j++)Add(Sum,mul(dp[j],iv[j+a[i]]));Add(ans,mul(a[i]*a[i],Sum));for(int j=m; j>=a[i]; j--)Dec(dp[j],dp[j-a[i]]);} cout <<mul(ans,mt);return0;}