BZOJ_4128_Matrix_矩阵乘法+哈希+BSGS

BZOJ_4128_Matrix_矩阵乘法+哈希+BSGS

Description

给定矩阵A,B和模数p,求最小的x满足

A^x = B (mod p)

Input

第一行两个整数n和p,表示矩阵的阶和模数,接下来一个n * n的矩阵A.接下来一个n * n的矩阵B

Output

输出一个正整数,表示最小的可能的x,数据保证在p内有解

Sample Input

2 7
1 1
1 0
5 3
3 2

Sample Output

4

HINT

对于100%的数据,n <= 70,p <=19997,p为质数,0<= A_{ij},B_{ij}< p
保证A有逆

把矩阵哈希,然后把它当成一个数一样做BSGS。
就是正常的乘法换成了矩乘。
然后因为矩阵的逆元我不会求,于是这里用的$a^{mp-q}$\%$n=b$这种形式
 
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <map>
using namespace std;
typedef unsigned long long ull;
ull base=13131;
int n,p;
map<ull,int>f;
struct Mat {
	ull v[75][75],val;
	Mat(){memset(v,0,sizeof(v)); val=0;}
	Mat operator*(const Mat &x) const {
		Mat re;int i,j,k;
		for(i=1;i<=n;i++) {
			for(j=1;j<=n;j++) {
				for(k=1;k<=n;k++) {
					(re.v[i][j]+=v[i][k]*x.v[k][j])%=p;
				}
			}
		}
		return re;
	}
	void hh() {
		int i,j;
		for(i=1;i<=n;i++) {
			for(j=1;j<=n;j++) {
				val=val*base+v[i][j];
			}
		}
	}
}A,B;
int main() {
	scanf("%d%d",&n,&p);
	int i,m=(int)ceil(sqrt(p)),j;
	for(i=1;i<=n;i++) for(j=1;j<=n;j++) scanf("%llu",&A.v[i][j]);
	for(i=1;i<=n;i++) for(j=1;j<=n;j++) scanf("%llu",&B.v[i][j]);
	A.hh(); B.hh();
	Mat I;
	for(i=1;i<=m;i++) {
		B=B*A;
		B.hh();
		f[B.val]=i;
	}
	Mat D;for(i=1;i<=n;i++) D.v[i][i]=1;
	for(i=1;i<=m;i++) D=D*A;
	for(i=1;i<=n;i++) I.v[i][i]=1;
	for(i=1;i<=m;i++) {
		I=I*D;
		I.hh();
		ull tmp=I.val;
		if(f.count(tmp)) {
			printf("%d\n",i*m-f[tmp]);return 0;
		}
	}
}

 

posted @ 2018-04-28 19:19  fcwww  阅读(216)  评论(0编辑  收藏  举报