[FJOI2007]轮状病毒
题目:洛谷P2144、BZOJ1002、codevs2886。
题目大意:给你n+1(n\le 100)个节点,除第一个节点外的所有节点围绕第一个节点排列成环装。中间的节点和所有节点都能连边,环上相邻两个节点也能连边。问该图生成树的数量(即有多少种不同方法能用n条边连接所有节点)。
以下是n=3时的16种方案。
解题思路:此题n小于等于100,但是无法迅速找到能求出解的方法。
此类题目通常都有规律。
我们发现,当n=1、2、3、4、5时,答案分别为1、5、16、45、121,即1^2,3^2-4,4^2,7^2-4,11^2。
不考虑减4的情况,观察底数,是不是斐波那契数列的形态?
那么我们递推出该斐波那契数列,然后求出第n项的平方。
然后发现,n为偶数时需要减去4,那么减去4即可。
这就是此题的规律。
结果非常大,要用高精度。
C++ Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | #include<cstdio> #include<cstring> using namespace std; #define ll long long struct bg{ ll a[700]; int len; }f[101]; void add(ll a[], int lena,ll b[], int lenb,ll c[], int & lenc){ lenc=lena; if (lenc<lenb)lenc=lenb; for ( int i=1;i<=lenc;++i){ c[i]+=a[i]+b[i]; c[i+1]+=c[i]/100000000; c[i]%=100000000; } while (c[lenc+1])++lenc; } void sqr$print(ll a[], int lena, int odd){ ll b[700]={0}; int lenb=(lena<<1)-1; for ( int i=1;i<=lena;++i) for ( int j=1;j<=lena;++j){ b[i+j-1]+=a[i]*a[j]; b[i+j]+=b[i+j-1]/100000000; b[i+j-1]%=100000000; } while (b[lenb+1])++lenb; while (!b[lenb])--lenb; if (!odd){ int now=1; b[1]-=4; while (b[now]<0){ b[now]+=100000000; --b[now++]; } } while (b[lenb+1])++lenb; while (!b[lenb])--lenb; printf ( "%d" ,( int )b[lenb]); for ( int i=lenb-1;i;--i) printf ( "%08d" ,( int )b[i]); putchar ( '\n' ); } int main(){ memset (f,0, sizeof f); int n; scanf ( "%d" ,&n); f[1].a[1]=f[1].len=f[2].len=1; f[2].a[1]=3; for ( int i=3;i<=n;++i) add(f[i-2].a,f[i-2].len,f[i-1].a,f[i-1].len,f[i].a,f[i].len); sqr$print(f[n].a,f[n].len,n&1); return 0; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步