• bzoj 4128: Matrix ——BSGS&&矩阵快速幂&&哈希


    题目

    给定矩阵A, B和模数p,求最小的正整数x满足 A^x = B(mod p).

    分析

    与整数的离散对数类似,只不过普通乘法换乘了矩阵乘法。

    由于矩阵的求逆麻烦,使用 $A^{km-t} = B(mod p)$ 形式的BSGS。

    然后就是判断矩阵是否相等,

    一种方法是对矩阵进行Hash,

    这里为了防止两个不同矩阵的Hash值冲突,使用了两个底数进行Hash。

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    typedef unsigned long long ull;
    const ull base1 = 100003 , base2 = 1000003;
    
    struct matrix
    {
        int r, c;
        int mat[75][75];
        ull h1, h2;
        matrix(){
            memset(mat, 0, sizeof(mat));
            h1 = h2 = 0;   //记得初始化
        }
    
        void Hash()
        {
            for(int i = 0;i < r;i++)
                for(int j = 0;j < c;j++)
                    h1 = h1 * base1 + mat[i][j], h2 = h2 * base2 + mat[i][j];
        }
    };
    int n, p;
    matrix A, B;
    
    matrix mul(matrix A, matrix B)   //矩阵相乘
    {
        matrix ret;
        ret.r = A.r; ret.c = B.c;
        for(int i = 0;i < A.r;i++)
            for(int k = 0;k < A.c;k++)
                for(int j = 0;j < B.c;j++)
                {
                    ret.mat[i][j] = (ret.mat[i][j] + A.mat[i][k] * B.mat[k][j]) % p;
                }
        return ret;
    }
    
    matrix mpow(matrix A, int n)
    {
        matrix ret;
        ret.r = A.r; ret.c = A.c;
        for(int i = 0;i < ret.r;i++)  ret.mat[i][i] = 1;
        while(n)
        {
            if(n & 1)  ret = mul(ret, A);
            A = mul(A, A);
            n >>= 1;
        }
        return ret;
    }
    
    map<pair<ull, ull>, int>mp;
    int BSGS(matrix A, matrix B, int p)
    {
        int m=sqrt(p)+1;mp.clear();
        matrix res= B;
        for(int i = 0;i < m;i++)
        {
            res.Hash();
            mp[make_pair(res.h1, res.h2)] = i;
            res = mul(A, res);
        }
        matrix mi = mpow(A, m);
        matrix tmp = mi;
        for(int i = 1;i <= m+1;i++)
        {
            tmp.Hash();
            pair<ull, ull> pa = make_pair(tmp.h1, tmp.h2);
            if(mp.count(pa))  return i*m - mp[pa];
            tmp = mul(tmp, mi);
        }
    }
    
    void debug_print(matrix a)
    {
        for(int i = 0;i < a.r;i++)
        {
            for(int j = 0;j < a.c;j++){
                printf("%d ", a.mat[i][j]);
            }
            printf("
    ");
        }
    }
    
    int  main()
    {
        //srand(NULL);
        scanf("%d%d", &n, &p);
        A.r = A.c = n;
        for(int i = 0;i < n;i++)
        for(int j = 0;j < n;j++){
            int tmp;
            scanf("%d", &tmp);
            A.mat[i][j] = tmp;
        }
        B.r = B.c = n;
        for(int i = 0;i < n;i++)
        for(int j = 0;j < n;j++){
            int tmp;
            scanf("%d", &tmp);
            B.mat[i][j] = tmp;
        }
    
    
        ///debug_print(A);
        //debug_print(B);
        //debug_print(R);
    
        printf("%d
    ", BSGS(A, B, p));
    }
    View Code

    另一种方法是随机产生一个n*1的矩阵f,若A*f=B*f我们则认为这两个矩阵是相等的。为了让直接map矩阵,还要写比较函数(奇怪的是,答案还受比较函数的影响)。

    注意矩阵的左乘和右乘。

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    struct matrix
    {
        int r, c;
        int mat[75][75];
        matrix(){
            memset(mat, 0, sizeof(mat));
        }
    
        bool operator < (const matrix &w) const     //???为什么会影响结果呢
        {
            for (int i=0;i< r;i++)
                if (mat[i][0]<w.mat[i][0]) return 0;
                else if (mat[i][0]>w.mat[i][0]) return 1;
            return 0;
        }
    };
    int n, p;
    matrix A, B, R;  //R是随机矩阵
    
    matrix mul(matrix A, matrix B)   //矩阵相乘
    {
        matrix ret;
        ret.r = A.r; ret.c = B.c;
        for(int i = 0;i < A.r;i++)
            for(int k = 0;k < A.c;k++)
                for(int j = 0;j < B.c;j++)
                {
                    ret.mat[i][j] = (ret.mat[i][j] + A.mat[i][k] * B.mat[k][j]) % p;
                }
        return ret;
    }
    
    matrix mpow(matrix A, int n)
    {
        matrix ret;
        ret.r = A.r; ret.c = A.c;
        for(int i = 0;i < ret.r;i++)  ret.mat[i][i] = 1;
        while(n)
        {
            if(n & 1)  ret = mul(ret, A);
            A = mul(A, A);
            n >>= 1;
        }
        return ret;
    }
    
    map<matrix, int>mp;
    int BSGS(matrix A, matrix B, matrix R, int p)
    {
        int m=sqrt(p)+1;mp.clear();
        matrix res=mul(B, R);
        for(int i = 0;i < m;i++)
        {
            mp[res] = i;
            res = mul(A, res);
        }
        matrix mi = mpow(A, m);
        matrix tmp = mi;
        for(int i = 1;i <= m+1;i++)
        {
            matrix t = mul(tmp, R);
            if(mp.count(t))  return i*m - mp[t];
            tmp = mul(tmp, mi);
        }
    }
    
    void debug_print(matrix a)
    {
        for(int i = 0;i < a.r;i++)
        {
            for(int j = 0;j < a.c;j++){
                printf("%d ", a.mat[i][j]);
            }
            printf("
    ");
        }
    }
    
    int  main()
    {
        //srand(NULL);
        scanf("%d%d", &n, &p);
        A.r = A.c = n;
        for(int i = 0;i < n;i++)
        for(int j = 0;j < n;j++){
            int tmp;
            scanf("%d", &tmp);
            A.mat[i][j] = tmp;
        }
        B.r = B.c = n;
        for(int i = 0;i < n;i++)
        for(int j = 0;j < n;j++){
            int tmp;
            scanf("%d", &tmp);
            B.mat[i][j] = tmp;
        }
    
        R.r = n, R.c = 1;
        for(int i = 0;i < n;i++)  R.mat[i][0] = rand()%(p-1) + p;
    
        ///debug_print(A);
        //debug_print(B);
        //debug_print(R);
    
        printf("%d
    ", BSGS(A, B, R, p));
    }
    View Code

    参考链接:

    1. SFN1036 zoj 4128:Matrix BSGS+矩阵乘法

    2. GXZlegend【bzoj4128】Matrix 矩阵乘法+Hash+BSGS

  • 相关阅读:
    算术运算符
    JAVA文件名命名规范
    JAVA构造函数的继承
    JAVA构造函数(方法)
    JAVA中的继承
    Linux下复制一个文件夹下文件到另外一个目录
    ISO-8601及GMT时间格式
    线程池执行任务后,返回值接收(转载)
    SpringBoot -> @Import引入配置类 @ImportResource引入xml配置文件
    Spring Boot与Spring Security整合后post数据不了,403拒绝访问
  • 原文地址:https://www.cnblogs.com/lfri/p/11490770.html
Copyright © 2020-2023  润新知