[FJOI2007]轮状病毒
题目描述
轮状病毒有很多变种。许多轮状病毒都是由一个轮状基产生。一个n轮状基由圆环上n个不同的基原子和圆心的一个核原子构成。2个原子之间的边表示这2个原子之间的信息通道,如图1。
n轮状病毒的产生规律是在n轮状基中删除若干边,使各原子之间有唯一一条信息通道。例如,共有16个不同的3轮状病毒,入图2所示。
给定n(N<=100),编程计算有多少个不同的n轮状病毒。
输入输出格式
输入格式:第一行有1个正整数n。
输出格式:将编程计算出的不同的n轮状病毒数输出
输入输出样例
输入样例#1:
复制
3
输出样例#1: 复制
16
其实可以用矩阵树定理来算方案数
但是没有取模,高精是必需的
实际每个矩阵都是相似的
1 5 16 45 121 320
归纳找到规律:
f[i]=3*f[i-1]-f[i-2]+2
证明
还有DP和高精度矩阵树(太毒了找不到)的做法
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 struct Num 8 { 9 int len; 10 int a[1001]; 11 }f[101]; 12 int n; 13 Num chen(Num a,int k) 14 { 15 int i; 16 Num ans; 17 for (i=1;i<=a.len;i++) 18 ans.a[i]=a.a[i]*k; 19 for (i=1;i<=a.len;i++) 20 ans.a[i+1]+=ans.a[i]/10,ans.a[i]%=10; 21 ans.len=a.len; 22 while (ans.a[ans.len+1]) 23 { 24 ans.len++; 25 ans.a[ans.len+1]+=ans.a[ans.len]/10; 26 ans.a[ans.len]%=10; 27 } 28 return ans; 29 } 30 Num add(Num a,int k) 31 { 32 int i; 33 Num ans; 34 for (i=1;i<=a.len;i++) 35 ans.a[i]=a.a[i]; 36 ans.len=a.len; 37 ans.a[1]+=k; 38 for (i=1;i<=a.len;i++) 39 ans.a[i+1]+=ans.a[i]/10,ans.a[i]%=10; 40 while (ans.a[ans.len+1]) 41 { 42 ans.len++; 43 ans.a[ans.len+1]+=ans.a[ans.len]/10; 44 ans.a[ans.len]%=10; 45 } 46 return ans; 47 } 48 Num jian(Num a,Num b) 49 { 50 int i; 51 Num ans; 52 ans.len=a.len; 53 for (i=1;i<=b.len;i++) 54 ans.a[i]=a.a[i]-b.a[i]; 55 for (i=b.len+1;i<=a.len;i++) 56 ans.a[i]=a.a[i]; 57 for (i=1;i<=a.len;i++) 58 { 59 if (ans.a[i]<0) ans.a[i]+=10,ans.a[i+1]-=1; 60 } 61 while (ans.a[ans.len]&&ans.len>1) ans.len--; 62 return ans; 63 } 64 int main() 65 {int i,j; 66 cin>>n; 67 f[1].a[1]=1;f[1].len=1; 68 f[2].a[1]=5;f[2].len=1; 69 for (i=3;i<=n;i++) 70 { 71 f[i]=chen(f[i-1],3); 72 f[i]=jian(f[i],f[i-2]); 73 f[i]=add(f[i],2); 74 } 75 for (i=f[n].len;i>=1;i--) 76 printf("%d",f[n].a[i]); 77 }