首页 技术 正文
技术 2022年11月16日
0 收藏 464 点赞 2,147 浏览 1985 个字

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4128

大水题一道

使用大步小步算法,把数字的运算换成矩阵的运算就好了

矩阵求逆?这么基础的线代算法我也不想多说,还是自行百度吧

需要注意的是矩阵没有交换律,所以在计算$B\cdot A^{-m}$的时候不要把顺序搞混

代码:

 #include <cstring>
#include <cstdio>
#include <algorithm>
#include <map>
#include <cmath> using namespace std;
const int MAXN = ; int n, p; struct Matrix {
int a[MAXN][MAXN];
int *operator[]( int idx ) {
return a[idx];
}
const int *operator[]( int idx ) const {
return a[idx];
}
bool operator<( const Matrix &rhs ) const { // 用于map
for( int i = ; i < n; ++i )
for( int j = ; j < n; ++j )
if( a[i][j] < rhs[i][j] ) return true;
else if( a[i][j] > rhs[i][j] ) return false;
return false;
}
void unit() { // 填成n阶单位矩阵
memset( a, , sizeof(a) );
for( int i = ; i < n; ++i ) a[i][i] = ;
}
void clear() { // 填成全0
memset( a, , sizeof(a) );
}
};
Matrix A, B; // 题目中给定的A,B矩阵 int pow_mod( int a, int b ) { // 整数快速幂
int ans = ;
while(b) {
if( b& ) ans = ans * a % p;
a = a * a % p;
b >>= ;
}
return ans;
}
int inv( int a ) { // 整数求逆
return pow_mod(a,p-);
}
void input_matrix( Matrix &A ) {
for( int i = ; i < n; ++i )
for( int j = ; j < n; ++j ) {
scanf( "%d", &A[i][j] );
A[i][j] %= p;
}
}
void mul( const Matrix &A, const Matrix &B, Matrix &C ) { // 矩阵乘法,结果存入C
Matrix tmp; tmp.clear();
for( int i = ; i < n; ++i )
for( int j = ; j < n; ++j )
for( int k = ; k < n; ++k )
tmp[i][j] = (tmp[i][j] + A[i][k] * B[k][j] % p) % p;
C = tmp;
}
void gauss_jordan( int A[MAXN][MAXN<<] ) { // 高斯约当消元求逆
for( int i = ; i < n; ++i ) {
int r;
for( r = i; r < n; ++r )
if( A[r][i] ) break;
if( r != i )
for( int j = i; j < (n<<); ++j )
swap( A[r][j], A[i][j] );
int iv = inv( A[i][i] );
for( int j = i; j < (n<<); ++j )
A[i][j] = A[i][j] * iv % p;
for( int j = ; j < n; ++j )
if( j != i && A[j][i] ) {
int tmp = (p - A[j][i]) % p;
for( int k = i; k < (n<<); ++k )
A[j][k] = (A[j][k] + A[i][k] * tmp % p) % p;
}
}
}
void inv( const Matrix &A, Matrix &B ) { // 矩阵求逆,结果存入B
int tmp[MAXN][MAXN<<] = {};
for( int i = ; i < n; ++i )
for( int j = ; j < n; ++j )
tmp[i][j] = A[i][j];
for( int i = ; i < n; ++i ) tmp[i][i+n] = ;
gauss_jordan(tmp);
for( int i = ; i < n; ++i )
for( int j = ; j < n; ++j )
B[i][j] = tmp[i][j+n];
} map<Matrix,int> mp;
int bsgs( Matrix A, Matrix B ) { // 大步小步算法
int m = sqrt(p)+;
Matrix E; E.unit();
for( int i = ; i < m; ++i ) {
if( !mp.count(E) ) mp[E] = i;
mul(E,A,E);
}
inv(E,E);
for( int i = ; i < p; i += m ) {
if( mp.count(B) ) return i + mp[B];
mul(B,E,B); // 注意矩阵乘法顺序
}
return -;
} int main() {
scanf( "%d%d", &n, &p );
input_matrix(A), input_matrix(B);
printf( "%d\n", bsgs(A,B) );
return ;
}
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:8,910
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,435
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,250
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,061
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,693
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,731