bzoj4128 Matrix BSGS

版权声明:虽然是个蒟蒻但是转载还是要说一声的哟 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;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/82889413