bzoj 4128: Matrix --BSGS && && hash matrix fast power

topic

Given a matrix A, B and the modulus p, find the smallest positive integer satisfying x A ^ x = B (mod p).

analysis

And integer discrete logarithm similar, but ordinary multiplication transfer matrix multiplication.

Since inverse matrix trouble, using the $ A ^ {km-t} = B (mod \ p) $ form BSGS.

Is then determined whether the same matrix,

One method is a matrix Hash,

In order to prevent conflicts Hash value here two different matrices used for the two base-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("\n");
    }
}

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\n", BSGS(A, B, p));
}
View Code

Another method is a random matrix f n * 1, if A * f = B * f We think that these two matrices are equal. In order to map directly to the matrix, but also to write a comparison function (Oddly enough, the answer is also affected by the comparison function).

Note that matrix multiplication of the left and right multiplication.

#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("\n");
    }
}

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\n", BSGS(A, B, R, p));
}
View Code

 

 

Reference links:

1. SFN1036 zoj 4128: the Matrix matrix multiplication BSGS +

2. GXZlegend] [bzoj4128 Matrix Matrix Multiplication + Hash + BSGS

 

Guess you like

Origin www.cnblogs.com/lfri/p/11490770.html