轉載請註明出處: http://www.cnblogs.com/fraud/ ——by fraudios
現場賽的時候因爲有個地方有點小問題,沒有成功AC,致使與金牌失之交臂。api
因爲今天下午有點事情,沒法打重現,因此下午只是花了十分鐘作了一道J題,搶了個FB,2333333333less
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 512000/512000 K (Java/Others)
Total Submission(s): 15 Accepted Submission(s): 3
ide
題意:規定每一個結點最多連3個點,有若干個結點構成一棵樹,則在樹的直徑爲k時,共有幾種非同構的結構。post
分析:因爲須要考慮非同構的狀況比較複雜,那麼,咱們能夠考慮將這棵樹拆開,先看偶數,偶數比較簡單ui
1.若直徑n爲偶數,則選取這棵樹的直徑的中間那條邊,將其斷開,從而產生長度均爲n/2的兩個分支,爲了保證計數時不會將同構的重複計入,根據組合數學,則方案數爲C(num[n/2]+2-1,2);spa
注:num[i]表示分支長度爲i的非同構的種數。code
dp[i]表示分支長度從0到i的全部非同構的分支方案數。orm
2.若直徑n爲奇數,則選取這棵樹的直徑上的中點,從而拆分紅長度爲(n-1)/2,長度爲(n-1)/2以及另外一條長度可爲0到(n-1)/2的三個分支。blog
a.若剩下一條分支的長度爲[0,(n-1)/2-1],根據組合數學,能夠獲得對應的方案數爲dp[(n-1)/2-1]*C(num[(n-1)/2]+2-1,2);
b.若剩下另外一條分支的長度也爲(n-1)/2,則此狀況下對應的方案數爲C(num[(n-1)/2]+3-1,3);
即奇數狀況爲dp[(n-1)/2-1]*C(num[(n-1)/2]+2-1,2)+C(num[(n-1)/2]+3-1,3);
接下來考慮num[i]與dp[i]是如何得出的問題:
顯然dp[i]只是一個前綴和,求出num[i]以後累加便可。
對於num[i],對於長度爲i的分支,其端點上只能鏈接兩個子分支(由於另外一個要留着與其它分支相連),那麼,對於長度爲i+1的分支,則只是在長度爲i的分支的端點處,增長了一個結點,而後再在新的端點上添加長度爲0到i的分支。
a.若添加的分支的長度爲0到i-1,則方案數爲num[i]*dp[i-1];
b.若添加的分支的長度爲i,則方案數爲C(num[i]+2-1,2);
即num[i+1]=num[i]*dp[i-1]+C(num[i]+2-1,2);
1 #include <iostream> 2 #include <sstream> 3 #include <ios> 4 #include <iomanip> 5 #include <functional> 6 #include <algorithm> 7 #include <vector> 8 #include <string> 9 #include <list> 10 #include <queue> 11 #include <deque> 12 #include <stack> 13 #include <set> 14 #include <map> 15 #include <cstdio> 16 #include <cstdlib> 17 #include <cmath> 18 #include <cstring> 19 #include <climits> 20 #include <cctype> 21 using namespace std; 22 #define XINF INT_MAX 23 #define INF 0x3FFFFFFF 24 #define MP(X,Y) make_pair(X,Y) 25 #define PB(X) push_back(X) 26 #define REP(X,N) for(int X=0;X<N;X++) 27 #define REP2(X,L,R) for(int X=L;X<=R;X++) 28 #define DEP(X,R,L) for(int X=R;X>=L;X--) 29 #define CLR(A,X) memset(A,X,sizeof(A)) 30 #define IT iterator 31 typedef long long ll; 32 typedef pair<int,int> PII; 33 typedef vector<PII> VII; 34 typedef vector<int> VI; 35 const int maxn=100010; 36 ll dp[maxn]; 37 ll num[maxn]; 38 const int mod=1000000007; 39 ll inv(int x) 40 { 41 int n=mod-2; 42 ll temp=x; 43 ll ret=1; 44 while(n) 45 { 46 if(n&1)ret=ret*temp%mod; 47 temp=temp*temp%mod; 48 n>>=1; 49 } 50 return ret; 51 } 52 int main() 53 { 54 ios::sync_with_stdio(false); 55 ll inv_2,inv_3; 56 inv_2=inv(2); 57 inv_3=inv(3); 58 dp[0]=num[0]=1; 59 dp[1]=num[1]=1; 60 for(int i=2;i<maxn;i++) 61 { 62 dp[i]=(num[i-1]*dp[i-2]%mod+(num[i-1]+1)*num[i-1]%mod*inv_2%mod)%mod; 63 dp[i-1]+=dp[i-2]; 64 dp[i-1]%=mod; 65 num[i]=dp[i]; 66 } 67 int n; 68 while(cin>>n&&n) 69 { 70 ll ans; 71 if(n==1)ans=1; 72 else if(n==2)ans=1; 73 else if(n&1) 74 { 75 ans=num[n/2]*(num[n/2]+1)%mod*inv_2%mod*dp[n/2-1]%mod; 76 ans+=num[n/2]*(num[n/2]+1)%mod*(num[n/2]+2)%mod*inv_2%mod*inv_3%mod; 77 ans%=mod; 78 } 79 else 80 { 81 ans=(num[n/2]*(num[n/2]+1))%mod*inv_2%mod; 82 } 83 cout<<ans<<endl; 84 } 85 return 0; 86 }