「Wdsr-2」白泽教育-题解
Subtask 1
前置芝士:大步小步算法(BSGS)
由高德纳箭号表示法的定义可得:
Subtask 2
前置芝士:扩展欧拉定理(exEuler)
我们首先来化简
我们首先来化简
由于欧拉函数嵌套多层后其值会变为
预处理欧拉函数的值,然后从
具体细节见代码注释。
代码:
#include <iostream>
#include <map>
#include <cmath>
using namespace std;
typedef long long ll;
typedef struct {
ll val;
bool flag;
} Node;
int phi[37];
map<ll, int> mp;
inline Node new_node(ll val, bool flag){
Node ans;
ans.val = val;
ans.flag = flag;
return ans;
}
inline Node quick_pow(ll x, ll p, ll mod){
Node ans;
ans.val = 1;
ans.flag = false;
while (p){
if (p & 1){
ans.val *= x;
if (ans.val >= mod){
ans.val %= mod;
ans.flag = true;
}
}
p >>= 1;
if (p == 0) break;
x *= x;
if (x >= mod){
x %= mod;
ans.flag = true;
}
}
return ans;
}
inline int bsgs(int a, int b, int p){
if (p == 1) return 0;
a %= p;
b %= p;
if (b == 1) return 0;
int m = ceil(sqrt(p)), i = 0;
ll t = quick_pow(a, m, p).val;
mp.clear();
for (register ll j = b; i < m; i++, j = j * a % p){
mp[j] = i;
}
i = 1;
for (register ll j = t; i <= m; i++, j = j * t % p){
if (mp.count(j)) return i * m - mp[j];
}
return -1;
}
inline int euler(int n){
int ans = n;
for (register int i = 2; i * i <= n; i++){
if (n % i == 0){
ans -= ans / i;
while (n % i == 0){
n /= i;
}
}
}
if (n > 1) ans -= ans / n;
return ans;
}
Node tetration(int a, int n, int index){
if (phi[index] == 1) return new_node(0, true);
if (n == 0) return new_node(1, false);
int next_index = index + 1;
Node x = tetration(a, n - 1, next_index);
if (x.flag) x.val += phi[next_index];
return quick_pow(a, x.val, phi[index]);
}
inline int f(int a){
if (a == 1) return 0;
for (register int i = 0; ; i++){
if (tetration(a, i, 0).flag) return i + 1;
}
}
inline ll quick_pow_with_max_val(ll x, ll p, ll max_val){
ll ans = 1;
while (p){
if (x >= max_val){
return max_val;
}
if (p & 1){
ans *= x;
if (ans >= max_val){
return max_val;
}
}
x *= x;
p >>= 1;
}
return ans;
}
ll tetration_with_max_val(ll a, ll n, int max_val){
if (n == 0 || a == 1) return 1;
ll x = tetration_with_max_val(a, n - 1, max_val);
if (x == max_val) return max_val;
return quick_pow_with_max_val(a, x, max_val);
}
ll pentation_with_max_val(ll a, ll n, int max_val){
if (n == 0 || a == 1) return 1;
ll x = pentation_with_max_val(a, n - 1, max_val);
if (x == max_val) return max_val;
return tetration_with_max_val(a, x, max_val);
}
inline ll pentation(ll a, ll n, int max_val, ll mod){
if (mod == 1) return 0;
if (n == 0) return 1;
return tetration(a, pentation_with_max_val(a, n - 1, max_val), 0).val % mod;
}
int main(){
int t;
cin >> t;
for (register int i = 1; i <= t; i++){
int a, n, b, p;
cin >> a >> n >> b >> p;
if (n == 1){
cout << bsgs(a, b, p) << endl;
} else {
int maxx_2 = 0, ans = -1;
for (register int j = p; j != 1; j = euler(j)){
phi[maxx_2++] = j;
}
phi[maxx_2] = 1;
if (n == 2){
for (register int j = 0; j <= maxx_2; j++){
if (tetration(a, j, 0).val == b){
ans = j;
break;
}
}
} else {
int maxx_3 = f(a);
for (register int j = 0; j <= maxx_3; j++){
if (pentation(a, j, maxx_2, p) == b){
ans = j;
break;
}
}
}
cout << ans << endl;
}
}
return 0;
}