写在前面:自这篇blog起,凡是各OJ上的题目就不放题目描述什么的了,直接给链接
传送门
思路:BSGS,由单个数字推广到矩阵
枚举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;}
}
}