对于只进行操作 1 和操作 2 的过程,设
f
i
,
j
,
k
(
k
≤
j
)
f_{i,j,k}(k \le j)
fi,j,k(k≤j) 表示已经加了
i
i
i 条边、有向链包含的点数为
j
j
j、前
k
k
k 个点已经被缩成一个点时的方案数, 易得转移:
f
i
,
j
,
k
=
f
i
−
1
,
j
−
1
,
k
+
∑
r
=
1
k
−
1
f
i
−
1
,
j
,
r
\begin{aligned} f_{i,j,k} = f_{i - 1, j - 1, k} + \sum \limits_{r = 1}^{k - 1}f_{i - 1, j,r} \end{aligned}
fi,j,k=fi−1,j−1,k+r=1∑k−1fi−1,j,r
对于只进行操作 2 和操作 3 的过程,设
g
i
,
k
g_{i,k}
gi,k 表示已经加了
i
i
i 条边、前
k
k
k 个点已经被缩成一个点时的方案数,易得转移:
g
i
,
k
=
f
i
,
n
,
k
+
∑
r
=
1
k
g
i
−
1
,
r
\begin{aligned} g_{i,k} = f_{i,n,k} + \sum \limits_{r = 1}^{k}g_{i - 1,r} \end{aligned}
gi,k=fi,n,k+r=1∑kgi−1,r
注意到操作 3 可以进行的次数不是无限的,因此我们需要限制状态中的
i
i
i 不能超过将前
k
k
k 个点缩成一个点时图中可能的最大边数,即:
i
≤
k
(
n
−
1
)
+
(
n
−
k
)
(
n
−
k
−
1
)
2
\begin{aligned} i \le k(n - 1) + \dfrac{(n - k)(n - k - 1)}{2} \end{aligned}
i≤k(n−1)+2(n−k)(n−k−1)
最后加入
i
i
i 条边的答案为:
a
n
s
i
=
∑
j
=
1
n
−
1
∑
k
=
1
j
f
i
,
j
,
k
+
∑
k
=
1
n
g
i
,
k
\begin{aligned} ans_i = \sum \limits_{j = 1}^{n - 1} \sum \limits_{k = 1}^{j} f_{i,j,k} + \sum \limits_{k = 1}^{n}g_{i,k} \end{aligned}
ansi=j=1∑n−1k=1∑jfi,j,k+k=1∑ngi,k
前缀和优化即可,显然
f
f
f 中的
i
i
i 只要枚举到
2
(
n
−
1
)
2(n - 1)
2(n−1),总的时间复杂度
O
(
n
3
)
\mathcal O(n^3)
O(n3)。
Code
#include<bits/stdc++.h>template<classT>inlinevoidread(T &res){char ch;while(ch =getchar(),!isdigit(ch));
res = ch ^48;while(ch =getchar(),isdigit(ch))
res = res *10+ ch -48;}template<classT>inlinevoidput(T x){if(x >9)put(x /10);putchar(x %10+48);}constint N =4e2+5;constint M =16e4+5;constint mod =1e9+7;int f[2][N][N], sf[2][N][N], g[M][N], ans[M], n, m;template<classT>inline T Min(T x, T y){return x < y ? x : y;}inlinevoidadd(int&x,int y){
x += y;
x >= mod ? x -= mod :0;}intmain(){read(n);if(n <=1)return0;
m = n *(n -1);
f[0][1][1]=1;for(int k =1; k <= n;++k)
sf[0][1][k]=1;for(int i =1, im = n -1<<1; i <= im;++i){int now = i &1, lst = now ^1;for(int j =1; j <= n;++j)for(int k =1; k <= j;++k)add(f[now][j][k]= f[lst][j -1][k], sf[lst][j][k -1]);for(int k =1; k <= n;++k)add(g[i][k], f[lst][n -1][k]);for(int j =1; j <= n;++j){for(int k =1; k <= n;++k){add(sf[now][j][k]= f[now][j][k], sf[now][j][k -1]);if(j < n)add(ans[i], f[now][j][k]);}}}for(int i = n -1; i <= m;++i){int res =0;for(int j =1; j <= n;++j){add(res, g[i -1][j]);if(i <= j *(n -1)+(n - j)*(n - j -1)/2)add(g[i][j], res);add(ans[i], g[i][j]);}}for(int i =1; i <= m;++i)put(ans[i]),putchar(' ');return0;}