【LOJ #6094. 「Codeforces Round #418」歸鄉迷途】
題目大意:
傳送門。
lca說的很明白就不重復了。
題解:
先膜一發lca。
大體讀完題以後我們可以知道對於第i個節點最短路一定是連向1到i-1中的某個點。
然後我們考慮將到1距離(這裏及以下均是最短路)相等的點放到同一層,顯然最後的總體結構應該是一棵樹,再加上在同一層/深度相同的點之間連接一些邊的並。
很容易發現一層的轉移只需要知道上一層度數為2/3的個數,以及當前層之間的相互連接。
先說一下$n^5$做法。
設$f_{i,p1,p2,u_1,u_2}$表示插入第i個點時,上一層度數為2/3還剩$p1/p2$,這一層度數為2/3還剩$u1/u2$,很顯然這個dp轉移是比較好(e)想(xin)的……
這裏就不寫了……
然後是lca大神的$n^3$。
我們發現在事實上,我們並不需要在向上連邊的同時和同層的連邊,我們只需要在把這一層向上連邊結束後計算一下當前層狀態到最後連邊狀態的方案即可。
設$f_{i,j}$表示前i個點中,最後j個點為最後1層,且前i-j個點度數已經滿足要求,但最後j個點只考慮向上一層如何連邊。
設$g_{i,j,k}$來表示新的一層插了i個的情況下,上一層有j個點度數為2,k個點度數為3。
所有有$f_{i,j}=\sum_k f_{i-j,k}*g_{j,c0,c1}$。其中c0/1表示上一層要求度數為2/3的個數。
假設我們知道了$g$那麽這個DP就是$n^3$。
1.顯然$g_{0,0,0}=1$。
2.考慮$g$當新的一層沒有節點時,即$i==0$,顯然此時狀態含義為當前層最後有度數2的點為$j$,3的點為$k$的方案數。此時,當$j==0$時,因為不會有度數為2的點,所以這次一定是一堆仍未在同層連接的點和最後一個添加點連成一個環。由於我們此時需要知道這個環的大小,所以我們得到:
$g_{0,0,k}=\sum_{l=2}^{k-1}g_{0,0,k-l-1}C_{k-1}^lN_{l+1}$。
這個表示最後狀態裏有$k$個三個度數的點由$k-l-1$個點的遞推。(應該很好理解)
$N_i$表示項鏈數,$i>=2$,即圓排列除以2。
3.考慮當$j!=0$時,我們最終狀態可以由$g_{0,j-2/j,k/k-1}$遞推而來,當我們這次選擇連接一個實際度數為1的點時,我們會產生兩個度數為2的點,當選擇實際度數為2的點時,我們會得到的一個度數為3和一個度數為2的點同時失去一個度數為2的點。同時由於之前選取集合的不同,此時我們得到:
$g_{0,j,k}=(j-1)g_{0,j-2,k}+k*g_{0,j,k-1}$。
4.當$i!=0$時,此時$g$回歸本來含義。我們很輕易地得出此時DP方程:
$g_{i,j,k}=j*g_{i-1,j-1,k}+k*g_{i-1,j+1,k-1}$
至此問題解決了。Orz lca大神犇。
代碼:
1 #include "bits/stdc++.h" 2 3 using namespace std; 4 5 inline int read() { 6 int s=0,k=1;char ch=getchar(); 7 while (ch<‘0‘|ch>‘9‘) ch==‘-‘?k=-1:0,ch=getchar(); 8 while (ch>47&ch<=‘9‘) s=s*10+(ch^48),ch=getchar(); 9 return s*k; 10 } 11 12 const int N=405,mod=1e9+7; 13 typedef long long ll; 14 15 int n,d[N]; 16 int f[N][N],g[N][N][N],fac[N],inv[N]; 17 18 #define C(a,b) (1ll*fac[a]*inv[b]%mod*inv[a-b]%mod) 19 20 inline void init() { 21 int i,j,k,s; 22 fac[0]=inv[1]=1; 23 inv[0]=1; 24 for (i=2;i<=n;++i) inv[i]=1ll*inv[mod%i]*(mod-mod/i)%mod; 25 for (i=1;i<=n;++i) fac[i]=1ll*fac[i-1]*i%mod; 26 for (i=1;i<=n;++i) inv[i]=1ll*inv[i-1]*inv[i]%mod; 27 g[0][0][0]=1; 28 for (i=0;i<=n;++i) 29 for (j=0;j<=n-i;++j) if(i||j){ 30 if (!i){ 31 for (k=2;k<j;++k)g[0][i][j]=(g[0][i][j]+C(j-1,k)*g[0][i][j-k-1]%mod*fac[k]%mod*inv[2])%mod; 32 }else { 33 if(i>=2)g[0][i][j]=(g[0][i][j]+(i-1ll)*g[0][i-2][j])%mod; 34 if(j>=1)g[0][i][j]=(g[0][i][j]+(ll)j*g[0][i-1][j-1])%mod; 35 } 36 } 37 38 for (i=1;i<n;++i) 39 for (s=1;s<n-i;++s) 40 for (k=0;k<=s;++k) { 41 j=s-k; 42 if (j) g[i][j][k]=(g[i][j][k]+(ll)j*g[i-1][j-1][k])%mod; 43 if (k) g[i][j][k]=(g[i][j][k]+(ll)k*g[i-1][j+1][k-1])%mod; 44 } 45 } 46 47 int main(){ 48 n=read(); 49 register int i,j,k; 50 int c[2]; 51 for (i=1;i<=n;++i) d[i]=read(); 52 init(); 53 f[d[1]+1][d[1]]=1; 54 for (i=d[1]+2;i<=n;++i) 55 for (j=1;j<=i-d[1]-1;++j) { 56 c[0]=c[1]=0; 57 for (k=1;k<i-j;++k) { 58 ++c[d[i-j-k+1]==3]; 59 f[i][j]=(f[i][j]+(ll)g[j][c[0]][c[1]]*f[i-j][k])%mod; 60 } 61 } 62 int ans=0; 63 c[0]=c[1]=0; 64 for (i=1;i<n;++i) { 65 ++c[d[n-i+1]==3]; 66 ans=(ans+(ll)f[n][i]*g[0][c[0]][c[1]])%mod; 67 } 68 printf("%d\n",ans); 69 }人家沒有抄代碼辣233
【LOJ #6094. 「Codeforces Round #418」歸鄉迷途】