zoukankan      html  css  js  c++  java
  • HDU 6185 Covering 矩阵快速幂 递推

      题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=6185

      题目描述: 一个4*n的矩形, 你用1*2的矩形覆盖有多少种方案, n <= 1e18

      解题思路: 自己看题一开始以为是轮廓线DP, 后来发现n实在是太大了....数组根本开不下, 后来觉得应该是一个矩阵快速幂, 可是递推式自己求不出来。 其实递推式应该打表出前十个n再去求, 因为我们这是一个线性递推式

        f(n) = k1 * f(n-1) + k2 * f(n-2) + ......  kw * f(n-w)

      我们从f(n-1) + f(n-2) 开始去找, 如果找到的k都是整数的话, 那这个递推式就是正确的, 因为这个递推式的几何意义表示在完成f(n-w)的前提下 前面那些有多少种方案, 而方案数一定是整数, 所以保证了正确性........现在我们先借助求得的前十个答案来求k, 当w = 2 , 3的情况下k都存在小数, 当w = 4的时候全部是整数

      代码:

    #include <iostream>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <cstring>
    #include <iterator>
    #include <cmath>
    #include <algorithm>
    #include <stack>
    #include <deque>
    #include <map>
    #define lson l, m, rt<<1
    #define rson m+1, r, rt<<1|1
    #define mem0(a) memset(a,0,sizeof(a))
    #define sca(x) scanf("%d",&x)
    #define de printf("=======
    ")
    typedef long long ll;
    using namespace std;
    
    const int maxn = 105;
    typedef double Matrix[maxn][maxn];
    Matrix A, X;
    
    void gauss(Matrix A,int n)
    {
        int i,j,k,r;
        for(int i=0; i<n; i++)
        {
            r=i;
            for( j=i+1; j<n; j++)
                if(fabs(A[j][i])>fabs(A[r][i]))r=j;
            if(r!=i)
                for(j=0; j<=n; j++)swap(A[r][j],A[i][j]);
            for(k=i+1; k<n; k++)
            {
                double f=A[k][i]/A[i][i];
                for(j=i; j<=n; j++)
                    A[k][j]-=f*A[i][j];
            }
        }
        for(i=n-1; i>=0; i--)
        {
            for(j=i+1; j<n; j++)
                A[i][n]-=A[j][n]*A[i][j];
            A[i][n]/=A[i][i];
        }
    }
    
    int main() {
        mem0(A);
        A[0][0]=95,A[0][1]=36,A[0][2]=11,A[0][3]=5,A[1][0]=6336,A[1][1]=2245,A[1][2]=781;
        A[1][3]=281,A[2][0]=781,A[2][1]=281,A[2][2]=95,A[2][3]=36,A[3][0]=2245,A[3][1]=781;
        A[3][2]=281,A[3][3]=95,A[0][4]=281,A[1][4]=18061,A[2][4]=2245,A[3][4]=6336;
        gauss(A, 4);
        for( int i = 0; i < 4; i++ ) {
            cout << A[i][4] << endl;
        }
        return 0;
    }
    求矩阵快速幂的系数

      系数是1, 5, 1, -1, 所以递推式就是f(n) = f(n-1)+5f(n-2)+f(n-3)-f(n-4)

      这时候我们就可以根据这个求矩阵快速幂的矩阵了...........

      写了一个多点儿......又出现BUG了.....不容易啊....

      代码: 

    #include <iostream>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <cstring>
    #include <iterator>
    #include <cmath>
    #include <algorithm>
    #include <stack>
    #include <deque>
    #include <map>
    #define lson l, m, rt<<1
    #define rson m+1, r, rt<<1|1
    #define mem0(a) memset(a,0,sizeof(a))
    #define sca(x) scanf("%d",&x)
    #define de printf("=======
    ")
    typedef long long ll;
    using namespace std;
    
    const ll mod = 1e9+7;
    const int maxn = 4;
    const int temp = 4;
    const int a[4] = {36,11,5,1};
    typedef struct {
        ll mat[maxn][maxn];
        void init() {
            mem0(mat);
            for( int i = 0; i < temp; i++ ) {
                for( int j = 0; j < temp; j++ ) {
                    if( i == j ) mat[i][j] = 1;
                }
            }
        }
    } Matrix;
    
    Matrix matrix = {1,5,1,-1,1,0,0,0,0,1,0,0,0,0,1,0};
    
    Matrix mul( Matrix m1, Matrix m2 ) {
        Matrix ret;
        mem0(ret.mat);
        for( int i = 0; i < temp; i++ ) {
            for( int j = 0; j < temp; j++ ) {
                for( int k = 0; k < temp; k++ ) {
                    ret.mat[i][j] = (ret.mat[i][j] + (m1.mat[i][k]*m2.mat[k][j])+mod) % mod;
                    //                cout << ret.mat[i][j] << endl;
                }
            }
        }
        return ret;
    }
    
    Matrix matrix_quick_power( Matrix m, ll times ) {
        Matrix ret;
        ret.init();
        while( times ) {
            if( times & 1 ) ret = mul( ret, m );
            times >>= 1;
            m = mul(m, m);
        }
        return ret;
    }
    
    
    int main() {
        //    debug(matrix);
        //    debug(matrix_quick_power( matrix, 1));
        ll n;
        while( cin >> n ) {
            if( n == 1 ) {
                cout << 1 << endl;
            }
            else if( n == 2 ) {
                cout << 5 << endl;
            }
            else if( n == 3 ) {
                cout << 11 << endl;
            }
            else if( n == 4 ) {
                cout << 36 << endl;
            }
            else {
                Matrix res;
                res.init();
                res = matrix_quick_power(matrix, n-4);
                ll ans = 0;
                for( int i = 0; i < 4; i++ ) {
                    ans = (ans + res.mat[0][i]*a[i] + mod) % mod;
                }
                cout << ans << endl;
            }
        }
        return 0;
    }
    矩阵快速幂

      思考: 这里明确一个问题, 我看到其他博客里会有这样的写法, typedef double Matrix[4][4], 这里解释一样, 这个时候Matrix 代表的就是一个4*4的整型数组, Matrix A , A就是那个数组, 但是和二维数组不一样的是, 这里的A可以传进函数里做实参, 但是为什么呢?, 然后我看到函数声明是这样显示的 double (*A)[], 这样就能作为实参传进去了吗........我还是很弱, 得多学点儿......真的菜................||分割 分割 分割||  刚才学长在群里说了一下想明白了......原来传的就是一个指针........如果想传实参的话用vector<vector<double>>就可以了.....OK, 过

  • 相关阅读:
    【转】系统缓存全解析二:动态缓存(4)-第三方分布式缓存解决方案 Velocity
    DevExpress.XtraTreeList.TreeList 的一些解决办法
    【转】系统缓存全解析二:动态缓存(4)-Discuz!NT中集成Memcached分布式缓存
    c#遍历Dictionary
    【转】memcached 命令概述
    WSAWaitforMultEvent使用
    创建线程是否调用CloseHandle
    小序
    select模式学习(二)之:客户端
    CoInitlize使用
  • 原文地址:https://www.cnblogs.com/FriskyPuppy/p/7462848.html
Copyright © 2011-2022 走看看