bzoj1002 生成树计数 找规律
这道题第一眼是生成树计数,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 }
——————————————————————————————————————————
去补习了一下python,用python写了一个用辗转相除思想算行列式的算法(感觉python还是挺快的,还有高精度支持)
1 #!/usr/bin/python 2 3 from math import * 4 5 6 def swap( a, b ): 7 return b, a 8 def abs( a ) : 9 if a<0 : 10 return -a 11 else: 12 return a 13 def det( a, n ): 14 for i in range(0,n): 15 if a[i][i]==0: 16 return 0 17 for j in range(i+1,n): 18 while a[j][i]!=0 : 19 d = a[i][i]//a[j][i] 20 for k in range(i,n) : 21 a[i][k] = a[i][k]-a[j][k]*d 22 a[j][k],a[i][k] = swap( a[j][k],a[i][k] ) 23 ans = 1 24 for i in range(0,n): 25 ans = ans * a[i][i] 26 return abs(ans) 27 28 def mod( a, m ): 29 return (a%m+m)%m 30 31 def main(): 32 for n in range( 1, 101 ): 33 if n==1 : 34 print 1 35 continue 36 if n==2 : 37 print 5 38 continue 39 40 i = j = 0 41 a = [ [ 0 for j in range(n) ] for i in range(n) ] 42 i = 0 43 for i in range(0,n): 44 a[i][i] = 3 45 a[i][mod(i-1,n)] = -1 46 a[i][mod(i+1,n)] = -1 47 print det(a,n) 48 main()
将文件保存到bzoj1002.py,执行
chmod +x hzoj1002.py
./hzoj1002.py