版权声明:虽然是个蒟蒻但是转载还是要说一声的哟 https://blog.csdn.net/jpwang8/article/details/82889413
Description
给定矩阵A,B和模数p,求最小的x满足
A^x = B (mod p)
对于100%的数据,n <= 70,p <=19997,p为质数,0<= A_{ij},B_{ij}< p
Solution
说个题外话,打模拟赛的时候遇到题解说可以nlogn求离散对数,本蒟蒻太菜了希望能有哪位大爷教教我这是什么黑科技。。。
考虑直接BSGS,关键在于如何比较两个矩阵是否相等。
一个可行的做法是我们钦定一个1*n的矩阵,让两个待比较的矩阵乘它,然后比较结果矩阵是否相等。这样比较是n^2的,并且正确率好像挺高。
另一个比较暴力的做法就是双哈希直接上咯
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <map>
#define rep(i,st,ed) for (register int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
#define fi first
#define se second
typedef long long LL;
typedef std:: pair <LL,LL> pair;
const int WJP1=1000000009;
const int WJP2=1000000007;
const int N=20005;
int MOD,n;
struct Mat {
int r[71][71];
void clear() {
rep(i,1,n) rep(j,1,n) r[i][j]=0;
}
void init() {
clear();
rep(i,1,n) r[i][i]=1;
}
Mat operator *(Mat B) {
Mat A=*this,C;
C.clear();
rep(i,1,n) rep(j,1,n) {
rep(k,1,n) C.r[i][j]+=A.r[i][k]*B.r[k][j]%MOD;
C.r[i][j]%=MOD;
}
return C;
}
Mat operator ^(LL dep) {
Mat A=*this,ret; ret.init();
for (;dep;dep>>=1) {
if (dep&1) ret=ret*A;
A=A*A;
}
return ret;
}
pair get() {
pair ret(pair(0,0)); LL gg=1;
rep(i,1,n) rep(j,1,n) {
ret.fi=(ret.fi*403219%WJP1+r[i][j])%WJP1;
ret.se=(ret.se*403181%WJP2+r[i][j])%WJP2;
}
return ret;
}
} A,B;
std:: map <pair,int> map;
int BSGS() {
int r=sqrt(MOD)+1;
Mat U,T; T=B;
rep(i,0,r) {
map[T.get()]=i;
T=T*A;
}
U.init();
Mat P=A^r;
rep(i,0,r) {
// U=A^(r*i);
int tmp=map[U.get()];
if (tmp) return r*i-tmp;
U=U*P;
}
return -1;
}
int main(void) {
// freopen("data.in","r",stdin);
scanf("%d%d",&n,&MOD);
A.init();
rep(i,1,n) rep(j,1,n) {
scanf("%d",&A.r[i][j]);
A.r[i][j]%=MOD;
}
rep(i,1,n) rep(j,1,n) {
scanf("%d",&B.r[i][j]);
B.r[i][j]%=MOD;
}
printf("%d\n", BSGS());
return 0;
}