BSGS 算法与 8.27 T1

BSGS 算法与 8.27 T1

Problem

给你三个整数 \(a,b,p\) 求最小的 \(x\in\N\) 使得 \(a^x\equiv b \pmod{p}\)\(a\perp p\)

Solution

要解决这个问题就要请出 \(BSGS\) 算法了,原理如下。

\(x=A\lceil\sqrt{p}\rceil-B\) 其中 \(0\le A,B\le \lceil\sqrt{p}\rceil\),则有 \(\large a^{A\lceil\sqrt{p}\rceil-B}\equiv b \pmod{p}\)

把指数上的 \(B\) 甩过去可得 \(\large a^{A\lceil\sqrt{p}\rceil}\equiv ba^B \pmod{p}\)

考虑枚举所有的 \(B\) ,算得每一个 \(ba^B\) ,把所有的 \(ba^B\) 甩进 \(hash\) 表里头,在枚举 \(A\) 看是否能凑出来 \(\large a^{A\lceil\sqrt{p}\rceil} \bmod p= ba^B\)

例题:8.27 测试 T1

Description

给你一个数 \(p\),缩剩余系是指由 \([1,p]\) 之间的与 \(p\) 互质的整数组成的集合。现在给你一个数 \(a\),求在模 \(p\) 意义下 \(a\) 的幂集有多少个不同的值。(形如 \(1, a, a^2, a^3, \ldots\) 的数叫做 \(a\) 的幂集 ) 其中 \(p\perp a\)

\(1 < p \leq 10^8\)\(T \leq 500\)

注意到在模 \(p\) 意义下 \(a\) 的幂集是会循环的,而题目中所求有多少个不同的值正是循环节的长度。

而又注意到 \(a^0 \equiv 1\pmod{p}\) 则问题变为求最小的 \(x\in\N_+\) 使得 \(a^x\equiv 1 \pmod{p}\)\(a\perp p\)

则可用 \(BSGS\) 算法解决。

#include<bits/stdc++.h>
#define int long long
using namespace std;
int ksm(int a,int b,int p){
	if(b==0) return 1;
	if(b==1) return a%p;
	int fk=ksm(a,b/2,p);
	if(b%2==0) return fk*fk%p;
	else return (((fk*fk)%p)*a)%p;
}  
int fq(int a,int b,int p){
	map<int,int> hash;
	hash.clear();
	b%=p;
	int t=(int) sqrt(p) +1;
	for(int j=0;j<t;j++){
		int val=b*ksm(a,j,p)%p;
		hash[val]=j;
	} 
	a=ksm(a,t,p)%p;
	if(a==0) return b==0 ? 1:-1;
	for(int i=1;i<=t;i++){//这里要从 1 开始,因为要求的 x 为正整数
		int val=ksm(a,i,p);
		int j=hash.find(val)==hash.end() ? -1:hash[val];
		if(j>=0 && i*t-j>=0) return i*t-j;
	}
	return -1;
} 
signed main(){
//	freopen("1th.in","r",stdin);
//	freopen("1th.out","w",stdout); 
	int t;
	cin>>t;
	while(t--){
		int p,a;
		cin>>p>>a;
		cout<<fq(a,1,p)<<endl;
	}
}

posted @ 2025-08-27 21:38  FQBC  阅读(20)  评论(0)    收藏  举报