group
10.20
30%
直接暴力算數列,直到遇到一個出現過的數,這樣後出現的數前面一定都出現過了,所以直接看當前出現的數有多少個不同即可。
複雜度: O(T mod)
100%
因爲gcd(a, mod) = 1,所以本質上那個數列是一個”環”,即是某一段數一直重複。
因爲a^(phi(n)) = 1(mod n),所以該最小循環節一定是phi(n)的約數(我們證明過的)。
所以我們可以直接枚舉所有phi(n)的約數,然後暴力check是否有a^d=1(mod)。
複雜度:O(T sqrt(mod) log(m))
本人的BSGS解法,ans = BSGS(a, inv[a], mod) + 1。(inv是逆元)。
#include <cstdio>
#include <cmath>
#include <cstring>
#include <iostream>
#define LL long long
using namespace std;
const LL S = 100007;
struct Hash_{
LL head[S], dest[S][2], last[S], etot;
void init(){
memset(head, 0, sizeof(head));
etot = 0;
}
void add(LL a, LL b){
LL key = a % S;
for(LL t=head[key]; t; t=last[t])
if(dest[t][0] == a) return;
etot++;
last[etot] = head[key];
dest[etot][0] = a;
dest[etot][1] = b;
head[key] = etot;
}
LL find(LL a){
LL key = a % S;
for(LL t=head[key]; t; t=last[t])
if(dest[t][0] == a) return dest[t][1];
return -1;
}
}hs;
void exgcd(LL a, LL b, LL &d, LL &x, LL &y) {
if(b == 0){
d = a; x = 1; y = 0;
}
else{
exgcd(b, a%b, d, y, x);
y -= a / b * x;
}
}
LL inverse(LL a, LL m){
LL x, y, d;
exgcd(a, m, d, x, y);
return (x % m + m) % m;
}
LL BSGS(LL a, LL b, LL m){//a^x = b(mod m)
hs.init();
LL sz = (LL)ceil( sqrt(b) + 1 );
LL cur = 1;
for(register LL i=0; i<sz; i++,cur=(1LL*cur*a)%m){
if(cur == b) return i;
hs.add(cur, i);
}
LL base = inverse(cur, m);
cur = 1LL * base * b % m;
for(register LL i=sz; i<=m-1; i+=sz,cur=(1LL*cur*base)%m) {
LL j = hs.find(cur);
if(j != -1 && (i+j)) return i + j;
}
return -1;
}
int main(){
freopen("group.in", "r", stdin);
freopen("group.out", "w", stdout);
LL T, a, p;
scanf("%I64d", &T);
while( T-- ){
scanf("%I64d%I64d", &a, &p);
LL ans = BSGS(a, inverse(a, p), p);
if(p == 1) ans = 0;//容易忽略的特判
printf("%I64d\n", ans+1);
}
return 0;
}