zoukankan      html  css  js  c++  java
  • 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( "
    " );
    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 }
    View Code

    ——————————————————————————————————————————

    去补习了一下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()
    View Code

    将文件保存到bzoj1002.py,执行

      chmod +x hzoj1002.py

      ./hzoj1002.py

  • 相关阅读:
    percona_xtrabackup
    利用java实现的一个发送手机短信的小例子
    使用mybatis执行oracle存储过程
    oracle 存储过程 基础
    oracle存储过程常用技巧
    oracle存储过程、声明变量、for循环|转|
    Oracle 存储过程
    mybatis 调用存储过程 返回游标 实例
    Spring Aop实例
    Struts2之自定义类型转换器
  • 原文地址:https://www.cnblogs.com/idy002/p/4293556.html
Copyright © 2011-2022 走看看