• HDU 1588 Gauss Fibonacci ★(矩阵 && 求和)


    题目大意:f(i)为fibonacci函数. g(i)=k*i+b,给定k,b,n,M求sum(f(g(i)) mod M for 0<=i<n   和这道题很像,不过这道题有个地方不好想点儿. 我们把sum展开 = f(b) + f(k+b) + f(2k+b) + …… + f((n-1)k+b). 到这儿我们发现这个和函数不像上题那么好看出递推规律……那么这题的难点就在这儿……   自己推的时候就隐约觉得他们存在某种关系,但就是想不出来,后来看了解题报告才明白了……   通常时候我做fibonacci递推时是用 ( f(n), f(n-1) ) = (1, 1, 1, 0)^(n-1) * (f(1), f(o)) , 这样的话就不好把f(n)表示成一个形式比较好的具体表达式,现在我们用另一种方法表示f(n), 把上面那个矩阵递推关系变形一下得:f(n) = (1, 1, 1, 0) ^ n 的右上角元素。 设A = (1, 1, 1, 0),我们就大胆的把f(n)表示成A^n (事实上这个正确性也好说明,因为求和用f(n)时都是加法,而加法是对应位置相加的,并不影响其他位置,也不会受其他位置影响,所以可以这样表示) 那么就有 sum = A^b + A^(k+b) + A^(2k+b) + …… + A^((n-1)k + b). 再变一下形式就很显然了: sum = A^b * (A^0 + A^k + A^2k + A^3k + …… + A^(n-1)k ) 如果我们定义SUM(A, n) = A^1 + A^2 + …… + A^n, 那么sum = A^b * ( E + SUM(A^k, n)  ).   (别忘了sum实际上是矩阵的右上角元素)  
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #define MID(x,y) ((x+y)>>1)
    using namespace std;
    typedef long long LL;
    
    const int MAX = 4;
    struct Mat{
        int row, col;
        LL mat[MAX][MAX];
    };
    //initialize square matrix to unit matrix
    Mat unit(int n){
        Mat A;
        A.row = A.col = n;
        memset(A.mat, 0, sizeof(A.mat));
        for (int i = 0; i < n; i ++)
            A.mat[i][i] = 1;
        return A;
    }
    //return T(A)
    Mat transpose(Mat A){
        Mat T;
        T.row = A.col;
        T.col = A.row;
        for (int i = 0; i < A.col; i ++)
            for (int j = 0; j < A.row; j ++)
                T.mat[i][j] = A.mat[j][i];
        return T;
    }
    //return (A+B)%mod
    Mat add(Mat A, Mat B, int mod){
        Mat C = A;
        for (int i = 0; i < C.row; i ++)
            for (int j = 0; j < C.col; j ++)
                C.mat[i][j] = (A.mat[i][j] + B.mat[i][j]) % mod;
        return C;
    }
    //return A*B%mod
    Mat mul(Mat A, Mat B, int mod){
        Mat C;
        C.row = A.row;
        C.col = B.col;
        for (int i = 0; i < A.row; i ++){
            for (int j = 0; j < B.col; j ++){
                C.mat[i][j] = 0;
                for (int k = 0; k < A.col; k ++)
                    //注意这里要保证乘法不溢出,否则还需要设计特殊的乘法模
                    C.mat[i][j] += A.mat[i][k] * B.mat[k][j];
                C.mat[i][j] %= mod;
            }
        }
        return C;
    };
    //return A^n%mod
    Mat exp_mod(Mat A, int n, int mod){
        Mat res = unit(A.row);
        while(n){
            if (n & 1){
                res = mul(res, A, mod);
            }
            A = mul(A, A, mod);
            n >>= 1;
        }
        return res;
    }
    //return S = A^1 + A^2 + …… + A^n   (binary search)
    Mat Sum(Mat A, int n, int mod){
        if (n == 1)
            return A;
        if (n & 1){
            return add(Sum(A, n-1, mod), exp_mod(A, n, mod), mod);
        }
        else{
            return mul(Sum(A, n/2, mod), add(exp_mod(A, n/2, mod), unit(A.col), mod), mod);
        }
    }
    int main(){
        int k, b, n, M;
        while(cin >> k >> b >> n >> M){
            Mat A;
            A.col = A.row = 2;
            A.mat[0][0] = 1;    A.mat[0][1] = 1;    A.mat[1][0] = 1;    A.mat[1][1] = 0;
            Mat Ab = exp_mod(A, b, M);
            Mat Ak = exp_mod(A, k, M);
            Mat E = unit(2);
            Mat SUM = Sum(Ak, n-1, M);
            Mat res = mul(Ab, add(E, SUM, M), M);
            cout << res.mat[0][1] << endl;
        }
    	return 0;
    }
    
     
    举杯独醉,饮罢飞雪,茫然又一年岁。 ------AbandonZHANG
  • 相关阅读:
    如何自己手写一个热加载(转)
    阻塞I/O、非阻塞I/O和I/O多路复用、怎样理解阻塞非阻塞与同步异步的区别?
    Java NIO浅析 转至 美团技术团队
    mysql在线修改表结构大数据表的风险与解决办法归纳(转)
    MySQL性能优化
    Tomcat Connector(BIO, NIO, APR)三种运行模式(转)
    redis 单线程的理解
    Spring 中的bean 是线程安全的吗?
    Spring 自定义注解,结合AOP,配置简单日志注解 (转)
    redis 分布式锁
  • 原文地址:https://www.cnblogs.com/AbandonZHANG/p/4113994.html
Copyright © 2020-2023  润新知