【BZOJ4128】Matrix,拔山盖世的矩阵乘法+随机化

写在前面:自这篇blog起,凡是各OJ上的题目就不放题目描述什么的了,直接给链接
传送门
思路:BSGS,由单个数字推广到矩阵
【BZOJ4128】Matrix,拔山盖世的矩阵乘法+随机化_第1张图片
枚举j,接下来有两种方法,一个是存哈希表,但蒟蒻觉得太麻烦,所以就学习了一下随机化,随便搞一个n×1的矩阵C,在等式两边同乘,变成(A^m)^i×C=B×A^j×C(注意顺序!不满足交换律!),然后枚举i,和得到的所有结果比较,碰到就可以输出了
主过程时间复杂度:存结果时O(2*n^2*√p)判断时O(√p*(n^2+√p*n)),好像是这个吧
能让n^3变成n^2,原本跑1.5s的程序就可以优化到0.6s左右了==,而且比hash快一些
代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map> 
using namespace std;
int n,p,m;
struct matrix
{
    int map[72][72];
}a,b,c,hash[145];
inline matrix mul(matrix a,matrix b)//快速幂时的乘法
{
    matrix c;
    memset(c.map,0,sizeof(c.map));
    for (int i=1;i<=n;i++)
    for (int j=1;j<=n;j++)
    for (int k=1;k<=n;k++)
    c.map[i][j]=(c.map[i][j]+a.map[i][k]*b.map[k][j]%p)%p;
    return c;
}
matrix cheng(matrix a,matrix b)//随机化后用的乘法
{
    matrix c;
    memset(c.map,0,sizeof(c.map));
    for (int j=1;j<=n;j++)
    for (int k=1;k<=n;k++)
    c.map[j][1]=(c.map[j][1]+a.map[j][k]*b.map[k][1]%p)%p;
    return c;
}
inline matrix qr(matrix x,int y)//矩阵快速幂
{
    matrix z=x;
    y--;
    while (y)
    {
        if (y&1) z=mul(z,x);
        x=mul(x,x);
        y>>=1;
    }
    return z;
}
inline bool pd(matrix x,matrix y)
{
    for (int i=1;i<=n;i++)
    if (x.map[i][1]!=y.map[i][1]) return 0;
    return 1;
}
main()
{
    scanf("%d%d",&n,&p);
    m=sqrt(p);
    for (int i=1;i<=n;i++)
    for (int j=1;j<=n;j++)
    scanf("%d",&a.map[i][j]);
    for (int i=1;i<=n;i++)
    for (int j=1;j<=n;j++)
    scanf("%d",&b.map[i][j]);
    for (int i=1;i<=n;i++) c.map[i][1]=i%p;
    for (int i=0;i<=m;i++)
    {
        hash[i]=cheng(b,c);
        c=cheng(a,c);
    }
    a=qr(a,m);
    for (int i=1;i<=n;i++) c.map[i][1]=i%p;
    for (int i=1;i<=m;i++)
    {
        c=cheng(a,c);
        for (int j=0;j<=m;j++)
        if (pd(hash[j],c)){printf("%d",i*m-j);return 0;}
    }
}

你可能感兴趣的:(【BZOJ4128】Matrix,拔山盖世的矩阵乘法+随机化)