首页 > 技术文章 > BZOJ 4128: Matrix

wuyuhan 2016-03-03 14:27 原文

BZOJ 4128: Matrix

标签(空格分隔): OI BZOJ 大步小步 矩阵 费马小定理


Time Limit: 10 Sec
Memory Limit: 128 MB


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有逆


Solution####

大步小步算法\({A^{x}\equiv B\pmod p}\)
\({A^{a\sqrt{p}-b}\equiv B\pmod p}\)
变换可得\({A^{a\sqrt{p}}\equiv B*A^{b}\pmod p}\)
\({A^{a\sqrt{p}}\pmod{p}}\)预处理
在hash表中查找和\({B*A^{b}\pmod{p}}\)相同的
时间复杂度\({n^{3}*\sqrt{p}}\)


Code####

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<bitset>
#include<vector>
using namespace std;
const int N=0,M=0;
int read()
{int s=0,f=1;char ch=getchar();
 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+ch-'0';ch=getchar();}
 return s*f;
}
//smile please
int n,P,L;
int cf[70];
struct matrix
{
    long long s[70][70];
 	void one()
       {
	    for(int i=0;i<n;i++)
		    for(int j=0;j<n;j++)
		        s[i][j]=(i==j);
	   }
    void readin()
       {
	    for(int i=0;i<n;i++)
		    for(int j=0;j<n;j++)
		        s[i][j]=read();
	   }
    int hash()
       {
       	int ss=0;
       	for(int i=0;i<n;i++)
		    for(int j=0;j<n;j++)
		       ss=ss*189211+s[i][j];
        return ss;
	   }
    void operator*=(matrix b)
       {matrix a;
        for(int i=0;i<n;i++)
		    for(int j=0;j<n;j++)
		        a.s[i][j]=s[i][j],
	            s[i][j]=0;
        for(int j=0;j<n;j++)
           {
		    for(int i=0;i<n;i++)cf[i]=b.s[i][j];
			for(int i=0;i<n;i++)
			   {
  			    for(int k=0;k<n;k++)
                   s[i][j]+=a.s[i][k]*cf[k];
	            s[i][j]%=P;
			   }
		   }
	   }
}A,B;
int he[1<<16],hn[1<<16],hv[1<<16],hl[1<<16],hw=1;
void put(int u,int v,int l)
{hw++;hn[hw]=he[u];he[u]=hw;hv[hw]=v;hl[hw]=l;}
int ans=0;
int main()
{
	n=read(),P=read();
	A.readin();B.readin();
    L=sqrt(P);ans=-1;
    matrix S=A,k=B;
    for(int i=1;i<=L;i++)
       {k*=A;if(i!=1)S*=A;
	    int ha=k.hash();
	    put(ha&((1<<16)-1),ha,i);
	   }
    matrix SS=S;
    for(int i=L;i<=P+L&&ans==-1;i+=L,SS*=S)
       {
        int ha=SS.hash();
        for(int j=he[ha&((1<<16)-1)];j&&ans==-1;j=hn[j])
           if(hv[j]==ha)
             ans=i-hl[j];
	   }
    if(ans==-1)
      printf("no solution\n");
    else
      printf("%d\n",ans);
	return 0;
}

推荐阅读