概述
传送门
题解:
由题目给出的两个限制:
1.从1到所有点的最短路唯一
2.1到 i i i的距离不小于1到 i + 1 i+1 i+1的距离
我们可以很显然地发现图可以这样生成:
- BFS树就是最短路树,且每个点向深度浅的边的连线只有一条
- 同层的点的编号连续,且非树边只可能是同层的点之间的连边。
设 f [ i ] [ j ] f[i][j] f[i][j]表示考虑前 i i i个点的时候,最后 j j j个点和 i i i点在同一层时候的方案数。
设 g [ i ] [ j ] [ k ] g[i][j][k] g[i][j][k]表示这一层有 i i i个点,上一层度数为 2 2 2的点有 j j j个,度数为 3 3 3的点有 k k k个,两层之间连边加上上一层层内连边的方案数,注意这里没有考虑当前层的点之间的连边,因为在考虑下一层的时候当前层的点有可能需要向下连边。
那么很显然,根据定义,最终答案为 ∑ i = 1 n − 1 f [ n ] [ i ] ∗ g [ 0 ] [ c 0 ] [ c 1 ] sumlimits_{i=1}^{n-1}f[n][i]*g[0][c0][c1] i=1∑n−1f[n][i]∗g[0][c0][c1],其中 c 0 , c 1 c0,c1 c0,c1分别表示最后 i i i个点中度数为 2 2 2和 3 3 3的点的个数。
同时对于 f f f,我们通过枚举上一层有多少个点,有一个可以 O ( n 3 ) O(n^3) O(n3)求解的式子:
f [ i ] [ j ] = ∑ k = 1 i − j − 1 f [ i − j ] [ k ] ∗ g [ j ] [ c 0 ] [ c 1 ] f[i][j]=sum_{k=1}^{i-j-1}f[i-j][k]*g[j][c0][c1] f[i][j]=k=1∑i−j−1f[i−j][k]∗g[j][c0][c1]
这里的 c 0 , c 1 c0,c1 c0,c1是从 i i i倒着数 k k k个的度数计数。
于是我们现在需要考虑的是 g g g的求解。
实际上 g g g也有一个 O ( n 3 ) O(n^3) O(n3)的求解方式。
显然 g [ 0 ] [ 0 ] [ 0 ] = 1 g[0][0][0]=1 g[0][0][0]=1。
然后,考虑 g [ 0 ] [ 0 ] [ k ] g[0][0][k] g[0][0][k]怎么算。由于现在只有度数为 3 3 3的点,不需要向下连出儿子边,每个点去掉向上的父亲边之后度数为 2 2 2。所以同层连边之后剩下的是若干个环,需要考虑旋转和翻折同构,实际上就是项链数,记长度为 i i i的非同构项链总数为 a i a_i ai。但是由于不允许重边,需要去掉长度为 2 2 2的环。
枚举这个点所在的环的长度,我们有:
g [ 0 ] [ 0 ] [ k ] = ∑ l = 3 k g [ 0 ] [ 0 ] [ k − l ] ⋅ ( k − 1 l − 1 ) ⋅ a l g[0][0][k]=sum_{l=3}^{k}g[0][0][k-l]cdot{k-1choose l-1}cdot a_l g[0][0][k]=l=3∑kg[0][0][k−l]⋅(l−1k−1)⋅al
考虑算 g [ 0 ] [ j ] [ k ] g[0][j][k] g[0][j][k]。现在,由于连了父亲边了,所有度数为 2 2 2的点还有一条自由边,度数为 3 3 3的点还有两条自由边,我们可以假设最后新加入的点度数为 2 2 2(其实 3 3 3也可以,但是转移情况有三种,考虑度数为 2 2 2的话只有两种),考虑这个加入的点有一条自由边,现在强制给这条边找到另一端。
如果从度数为
2
2
2的点中选择的话方案数显然是
j
−
1
j-1
j−1,转化成子问题
g
[
0
]
[
j
−
2
]
[
k
]
g[0][j-2][k]
g[0][j−2][k]。
如果从度数为
3
3
3的点中选择的话,这个点的自由边就只剩下一条,相当于度数为
2
2
2的点,方案数为
k
k
k,转化为子问题
g
[
0
]
[
j
]
[
k
−
1
]
g[0][j][k-1]
g[0][j][k−1]。
所以我们得到第二个转移式:
g [ 0 ] [ j ] [ k ] = g [ 0 ] [ j − 2 ] [ k ] ⋅ ( j − 1 ) + g [ 0 ] [ j ] [ k − 1 ] ⋅ k g[0][j][k]=g[0][j-2][k]cdot(j-1)+g[0][j][k-1]cdot k g[0][j][k]=g[0][j−2][k]⋅(j−1)+g[0][j][k−1]⋅k
现在考虑求 g [ i ] [ j ] [ k ] g[i][j][k] g[i][j][k]。其实这里还挺简单的,我们考虑在上一层中选择一个点作为他的父亲,那么他的父亲就要少一条自由边,直接考虑一下选择度数为 2 2 2还是 3 3 3,随便做就行了,则有如下转移:
g [ i ] [ j ] [ k ] = g [ i − 1 ] [ j − 1 ] [ k ] ⋅ j + g [ i − 1 ] [ j + 1 ] [ k − 1 ] ⋅ k g[i][j][k]=g[i-1][j-1][k]cdot j+g[i-1][j+1][k-1]cdot k g[i][j][k]=g[i−1][j−1][k]⋅j+g[i−1][j+1][k−1]⋅k
总复杂度
O
(
n
3
)
O(n^3)
O(n3),所以为什么才给n=50
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
using std::cerr;
using std::cout;
cs int mod=1e9+7;
inline int add(int a,int b){return (a+=b)>=mod?a-mod:a;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline bool Inc(int &a,int b){return (a+=b)>=mod&&(a-=mod);}
inline bool Dec(int &a,int b){return (a-=b)<0&&(a+=mod);}
cs int N=55;
int n,ans;
int g[N][N][N],f[N][N],d[N];
int c[N][N],a[N];
inline void init(){
c[0][0]=1;
for(int re i=1;i<=n;++i){
c[i][0]=c[i][i]=1;
for(int re j=1;j<i;++j)c[i][j]=add(c[i-1][j],c[i-1][j-1]);
}
a[2]=a[3]=1;
for(int re i=4;i<=n;++i)a[i]=mul(a[i-1],i-1);
g[0][0][0]=1;
for(int re k=1;k<=n;++k)
for(int re l=3;l<=k;++l)
Inc(g[0][0][k],mul(g[0][0][k-l],mul(c[k-1][l-1],a[l])));
for(int re j=1;j<=n;++j)
for(int re k=0,lk=n-j;k<=lk;++k)
(j>=2)&&Inc(g[0][j][k],mul(g[0][j-2][k],j-1)),
(k>=1)&&Inc(g[0][j][k],mul(g[0][j][k-1],k));
for(int re i=1;i<=n;++i)
for(int re j=0,lj=n-i;j<=lj;++j)
for(int re k=0,lk=lj-j;k<=lk;++k)
j&&Inc(g[i][j][k],mul(g[i-1][j-1][k],j)),
k&&Inc(g[i][j][k],mul(g[i-1][j+1][k-1],k));
}
signed main(){
scanf("%d",&n);
for(int re i=1;i<=n;++i)scanf("%d",d+i);
init();
f[d[1]+1][d[1]]=1;
for(int re i=d[1]+2;i<=n;++i)
for(int re j=1,lj=i-d[1]-1;j<=lj;++j)
for(int re k=1,lk=i-j,c0=0,c1=0;k<lk;++k){
++(d[i-j-k+1]==2?c0:c1);
Inc(f[i][j],mul(f[i-j][k],g[j][c0][c1]));
}
for(int re i=1,c0=0,c1=0;i<n;++i){
++(d[n-i+1]==2?c0:c1);
Inc(ans,mul(f[n][i],g[0][c0][c1]));
}
cout<<ans<<"n";
return 0;
}
最后
以上就是俏皮烧鹅为你收集整理的【CF814E】 An unavoidable detour for home(组合数学)(DP)传送门题解:的全部内容,希望文章能够帮你解决【CF814E】 An unavoidable detour for home(组合数学)(DP)传送门题解:所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复