这道题第一眼是生成树计数,n是100,是可以用O(n^3)的求基尔霍夫矩阵的n-1阶的子矩阵的行列式求解的,但是题目中并没有说取模之类的话,就不好办了。
用高精度?有分数出现。
用辗转相除的思想,让它不出现分数。但过程中会出现负数,高精度处理负数太麻烦。
用Python打表?好吧,Python还不熟,写不出来。。。。。
所以,如果这道题我考场上遇到,最多用double骗到n<=20的情况的部分分。
最终只能求助于题解了。。。
好像是通过观察行列式的特点,推导出关于答案f(n)的递推式(f(n)=3*f(n-1)-f(n-2)+2)
这道题就这样水过了,收获是:
1、题目可能属于某一类问题,该类问题又有通法可解,但题目一般不能直接套用之,此时就只能观察题目较之一般问题的特殊之处,尝试利用它帮助解题。
2、当1行不通时,可以先用暴力把规模较小的解跑出来,再看看可否推出规律。
回顾一下高精:
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #define M 10 5 using namespace std; 6 7 struct Num { 8 int v[100], len; 9 Num(){} 10 Num( int n ) { 11 memset( v, 0, sizeof(v) ); 12 if( n==0 ) { 13 len = 1; 14 return; 15 } 16 len = 0; 17 while( n ) { 18 len++; 19 v[len] = n%M; 20 n /= M; 21 } 22 } 23 Num operator+( const Num &b ) const { 24 Num rt(0); 25 rt.len = max( len, b.len ) + 1; 26 for( int i=1; i<=rt.len; i++ ) { 27 rt.v[i] += v[i]+b.v[i]; 28 rt.v[i+1] += rt.v[i]/M; 29 rt.v[i] %= M; 30 } 31 while( rt.len>1 && rt.v[rt.len]==0 ) rt.len--; 32 return rt; 33 } 34 Num operator-( const Num &b ) const { 35 Num rt(0); 36 rt.len = len; 37 for( int i=1; i<=rt.len; i++ ) { 38 rt.v[i] += v[i]-b.v[i]; 39 if( rt.v[i]<0 ) { 40 rt.v[i]+=M; 41 rt.v[i+1]--; 42 } 43 } 44 while( rt.len>1 && rt.v[rt.len]==0 ) rt.len--; 45 return rt; 46 } 47 int count_bit( int b ) const { 48 int rt = 0; 49 while( b ) { 50 rt++; 51 b/=M; 52 } 53 return rt; 54 } 55 Num operator*( int b ) const { 56 Num rt(0); 57 rt.len = len+count_bit(b)+1; // b==3 58 for( int i=1; i<=rt.len; i++ ) { 59 rt.v[i] += v[i]*b; 60 rt.v[i+1] += rt.v[i]/M; 61 rt.v[i] %= M; 62 } 63 while( rt.len>1 && rt.v[rt.len]==0 ) rt.len--; 64 return rt; 65 } 66 void print() { 67 for( int i=len; i>=1; i-- ) 68 printf( "%d", v[i] ); 69 printf( "\n" ); 70 } 71 }; 72 73 int n; 74 Num dp[110]; 75 76 int main() { 77 scanf( "%d", &n ); 78 dp[1] = Num(1); 79 dp[2] = Num(5); 80 for( int i=3; i<=n; i++ ) 81 dp[i] = dp[i-1]*3 +Num(2) - dp[i-2]; 82 dp[n].print(); 83 }
原文:http://www.cnblogs.com/idy002/p/4293556.html