zoukankan      html  css  js  c++  java
  • hdu 4291矩阵快速幂

    这题是去年成都网络赛的题,当时没做出来,杯具呀。

    其实最关键的就是要懂得取余一定会循环的,如果能够找出循环节,就是一个巨大的突破。然后就是g(n)的求法,很显然硬求是不可能的,我们去年做这题的时候试图去找g(n)的通项公式,都找得差不多了,但实际上那毫无意义。因为我们是要找循环节,所以应该一层层地找。先看g(n) % 1000000007到哪里会循环。可以用矩阵的方法求g(n),暴力打出来,发现循环节是222222224。再来看g(g(n)) % 1000000007到哪里会循环。因为g(g(n)) % 1000000007对g(n)每隔222222224结果就会循环一次,所以g(g(n)) % 1000000007 = g(g(n) % 222222224) % 1000000007。所以g(n) % 222222224的循环节也就是g(g(n)) % 1000000007的循环节。暴力求出来是183120。最后再看g(g(g(n))) % 1000000007的循环节。同理g(n) % 183120的循环节就是g(g(g(n))) % 1000000007的循环节。暴力求出来是240。也就是说,最后的结果,n每隔240就会循环。所以最后的结果就是g(g(g(n % 240) % 183120) % 222222224) % 1000000007。用矩阵快速幂就可以过了。

    我的暴力求循环节的代码如下:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <ctime>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <set>
    #include <map>
    #include <stack>
    #include <string>
    #include <vector>
    #include <deque>
    #include <list>
    #include <functional>
    #include <numeric>
    #include <cctype>
    using namespace std;
    const int MAX_ORDER = 2;
    const int MOD = 1000000007;
    typedef long long typec;
    typedef struct MyMatrix {
        int row, col;
        typec num[MAX_ORDER][MAX_ORDER];
        MyMatrix(int rr, int cc) {
            row = rr;
            col = cc;
        }
        inline void init() {
            memset(num, 0, sizeof(num));
        }
    } MyMatrix;
    //矩阵乘法。注意:ma.col与mb.row一定要相等,否则会出问题
    MyMatrix operator*(MyMatrix ma, MyMatrix mb) {
        int row = ma.row;
        int col = mb.col;
        int K = ma.col;
        MyMatrix numc(row, col);
        numc.init();
        int i, j, k;
        for (i = 0; i < row; i++) {
            for (j = 0; j < col; j++) {
                for (k = 0; k < K; k++) {
                    numc.num[i][j] += ma.num[i][k] * mb.num[k][j];
                    numc.num[i][j] %= MOD;
                }
            }
        }
        return numc;
    }
    //矩阵快速幂。注意:ma.col与ma.row一定要相等,否则会出问题
    MyMatrix mpow(MyMatrix ma, int x) {
        int ord = ma.row;
        MyMatrix numc(ord, ord);
        numc.init();
        for (int i = 0; i < ord; i++) {
            numc.num[i][i] = 1;
        }
        for (; x; x >>= 1) {
            if (x & 1) {
                numc = numc * ma;
            }
            ma = ma * ma;
        }
        return numc;
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("data.in", "r", stdin);
    #endif
        MyMatrix ori(1, 2);
        ori.num[0][0] = 0;
        ori.num[0][1] = 1;
        MyMatrix tran(2, 2);
        tran.num[0][0] = 0;
        tran.num[0][1] = 1;
        tran.num[1][0] = 1;
        tran.num[1][1] = 3;
        for(int t = 1; ; t++) {
            ori = ori * tran;
            if(ori.num[0][0] == 0 && ori.num[0][1] == 1) {
                printf("%d\n", t);
                break;
            }
        }
        return 0;
    }

    最后通过的代码如下:

    /*
     * hdu4291/win.cpp
     * Created on: 2012-11-4
     * Author    : ben
     */
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <ctime>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <set>
    #include <map>
    #include <stack>
    #include <string>
    #include <vector>
    #include <deque>
    #include <list>
    #include <functional>
    #include <numeric>
    #include <cctype>
    using namespace std;
    const int MAX_ORDER = 2;
    int MOD;
    typedef long long typec;
    typedef struct MyMatrix {
        int row, col;
        typec num[MAX_ORDER][MAX_ORDER];
        MyMatrix(int rr, int cc) {
            row = rr;
            col = cc;
        }
        inline void init() {
            memset(num, 0, sizeof(num));
        }
    } MyMatrix;
    //矩阵乘法。注意:ma.col与mb.row一定要相等,否则会出问题
    MyMatrix operator*(MyMatrix ma, MyMatrix mb) {
        int row = ma.row;
        int col = mb.col;
        int K = ma.col;
        MyMatrix numc(row, col);
        numc.init();
        int i, j, k;
        for (i = 0; i < row; i++) {
            for (j = 0; j < col; j++) {
                for (k = 0; k < K; k++) {
                    numc.num[i][j] += ma.num[i][k] * mb.num[k][j];
                    numc.num[i][j] %= MOD;
                }
            }
        }
        return numc;
    }
    //矩阵快速幂。注意:ma.col与ma.row一定要相等,否则会出问题
    MyMatrix mpow(MyMatrix ma, int x) {
        int ord = ma.row;
        MyMatrix numc(ord, ord);
        numc.init();
        for (int i = 0; i < ord; i++) {
            numc.num[i][i] = 1;
        }
        for (; x; x >>= 1) {
            if (x & 1) {
                numc = numc * ma;
            }
            ma = ma * ma;
        }
        return numc;
    }
    
    inline MyMatrix getori() {
        MyMatrix ori(1, 2);
        ori.num[0][0] = 0;
        ori.num[0][1] = 1;
        return ori;
    }
    
    inline MyMatrix gettran() {
        MyMatrix tran(2, 2);
        tran.num[0][0] = 0;
        tran.num[0][1] = 1;
        tran.num[1][0] = 1;
        tran.num[1][1] = 3;
        return tran;
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("data.in", "r", stdin);
    #endif
        long long temp;
        while(scanf("%I64d", &temp) == 1) {
            int n = (int)(temp % 240);
            MOD = 183120;
            n = (getori() * mpow(gettran(), n)).num[0][0];
            MOD = 222222224;
            n = (getori() * mpow(gettran(), n)).num[0][0];
            MOD = 1000000007;
            n = (getori() * mpow(gettran(), n)).num[0][0];
            printf("%d\n", n);
        }
        return 0;
    }
  • 相关阅读:
    小程序 图片和文字放在一行对齐的方法
    Linux下Redis安装使用教程
    关系型数据库和非关系型数据库的区别
    微信小程序scroll-view 横向和纵向scroll-view组件
    ThinkPHP5.0手把手实现手机阿里云短信验证
    极验(Geetest) Laravel 5 集成开发包,让验证更安全
    (进阶篇)PHP(thinkphp5框架)实现用户注册后邮箱验证,激活帐号
    详解PhpSpreadsheet设置单元格
    使用PhpSpreadsheet将Excel导入到MySQL数据库
    【JZOJ4783】【NOIP2016提高A组模拟9.15】Osu
  • 原文地址:https://www.cnblogs.com/moonbay/p/2753465.html
Copyright © 2011-2022 走看看