BZOJ 4128 Matrix Baby-Step-Giant-Step+矩阵求逆

来源:互联网 发布:海南环岛高铁停运 知乎 编辑:程序博客网 时间:2024/04/30 07:21

题目大意:给定两个nn的矩阵AB,求一个最小的非负整数x满足AxB( mod p)
保证[0,p]内有解
这个问题类似于离散对数问题,因此可以用BSGS来解决
但是和离散对数要求逆元一样,这个问题需要求出矩阵的逆
之前一直只会O(n5)的方法- - 今天特意去学了O(n3)
做法如下:
A矩阵的右侧接一个单位矩阵I 变成一个n2n的矩阵(A|I)
然后通过初等行变换将左侧的A变成单位矩阵I
此时右侧的单位矩阵I就变成了A1
(其实和高斯消元解线性方程组是一样的,只不过把右侧的答案列向量变成了单位矩阵I)
然后就简单了- -
(像我这种连BSGS都写不对的傻逼赶紧退役吧

#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define M 71#define BASE1 233#define BASE2 2333#define MOD 1001001using namespace std;int n,p,inv[20000];inline void Assert(bool flag){    if(flag) return ;    while(1) puts("Fuck♂You!");}struct Matrix{    int a[M][M];    Matrix() {}    Matrix(bool flag)    {        memset(a,0,sizeof a);        int i;        for(i=1;i<=n;i++)            a[i][i]=flag;    }    int* operator [] (int x)    {        return a[x];    }    friend bool operator == (Matrix x,Matrix y)    {        int i,j;        for(i=1;i<=n;i++)            for(j=1;j<=n;j++)                if(x[i][j]!=y[i][j])                    return false;        return true;    }    friend Matrix operator * (Matrix x,Matrix y)    {        Matrix z(0);        int i,j,k;        for(i=1;i<=n;i++)            for(j=1;j<=n;j++)                for(k=1;k<=n;k++)                    (z[i][j]+=x[i][k]*y[k][j])%=p;        return z;    }    friend Matrix Inverse(Matrix a)//We assume that the matrix x is inversible    {        Matrix re(true);        int i,j,k;        for(i=1;i<=n;i++)        {            for(k=i;k<=n;k++)                if(a[k][i])                    break;            Assert(k!=n+1);            for(j=1;j<=n;j++)            {                swap(a[i][j],a[k][j]);                swap(re[i][j],re[k][j]);            }            int inv=::inv[a[i][i]];            for(j=1;j<=n;j++)            {                (a[i][j]*=inv)%=p;                (re[i][j]*=inv)%=p;            }            for(k=1;k<=n;k++)                if(k!=i)                {                    int temp=(p-a[k][i])%p;                    for(j=1;j<=n;j++)                    {                        (a[k][j]+=temp*a[i][j])%=p;                        (re[k][j]+=temp*re[i][j])%=p;                    }                }        }        return re;    }    int Hash()    {        int i,j,re=0;        for(i=1;i<=n;i++)        {            long long temp=0;            for(j=1;j<=n;j++)                temp=(temp*BASE1+a[i][j])%MOD;            re=((long long)re*BASE2+temp)%MOD;        }        return re;    }}A,B;namespace Hash_Table{    struct List{        Matrix x;        int val;        List *next;        List(Matrix _,List *__):            x(_),val(0x3f3f3f3f),next(__) {}    }*head[1001001];    int& Hash(Matrix x)    {        int pos=x.Hash();        List *temp;        for(temp=head[pos];temp;temp=temp->next)            if(temp->x==x)                return temp->val;        return (head[pos]=new List(x,head[pos]))->val;    }}void Linear_Shaker(){    int i;    for(inv[1]=1,i=2;i<p;i++)        inv[i]=(p-p/i)*inv[p%i]%p;}int Baby_Step_Giant_Step(){    int i,m=ceil(sqrt(p))+1;    Matrix D(true);    for(i=0;i<m;i++,D=D*A)    {        int &val=Hash_Table::Hash(D);        val=min(val,i);    }    Matrix temp(true);    for(i=0;i<=m;i++,temp=temp*D)    {        Matrix X=Inverse(temp)*B;        int &val=Hash_Table::Hash(X);        if(val!=0x3f3f3f3f)            return i*m+val;    }    Assert(false);}int main(){    int i,j;    cin>>n>>p;    Linear_Shaker();    for(i=1;i<=n;i++)        for(j=1;j<=n;j++)            scanf("%d",&A[i][j]);    for(i=1;i<=n;i++)        for(j=1;j<=n;j++)            scanf("%d",&B[i][j]);    cout<<Baby_Step_Giant_Step()<<endl;    return 0;}
0 0