/**
题意:给出一个整数sum, 查询q,每个查询有一对(x, y), 问满足x ^ k = y(mod p) 的最小的K是多少,不存在的话输出-1,其中p是sum的质因子
思路:有个baby-step-giant-step算法, 求高次同余方程A ^ x = B (mod p)最小的x, 因为p是素数, 那么有生成元g,使得g^a=A,g^b = B,生成元可以预处理, 那么得出a * x = b (mod p-1), 这是扩展欧几里得,因为sum <= 1e8, 那么>1e4的素数最多只有一个, 最这个特殊处理, 小的暴力解决, 对这个生成元g预处理之后,可以快速查找到a, b的值,然后就可以了。
*/
#include<bits/stdc++.h>
typedef long long ll;
const ll maxn = 1e6 + 10;
const ll INF = 1e9 + 10;
using namespace std;
ll prime[maxn], res[30][10010], num;
const ll hash_size = 1000101;
ll exgcd(ll a, ll mod, ll y) { ///a * x = y % mod, 1求x
ll X = a, Y = mod, md, q, xi, ansx = 1, ansy = 0;
while(1) {
q = X / Y; md = X - Y * q;
if(!md) break;
xi = ansx - q * ansy; ansx = ansy; ansy = xi;
X = Y; Y = md;
}
ansy %= mod; if(ansy < 0) ansy += mod;
if(y % Y) return -1; ///Y是最大公约数
ansy = (ansy * y / Y) % (mod / Y);
return ansy; ///ansy是逆元
}
struct HASH_TABLE {
ll top, gm, inv, m, pri;
ll hash_table[hash_size], mp[hash_size];
ll head[hash_size], nxt[hash_size];
void init() {
top = 1;
memset(hash_table, 0, sizeof hash_table);
memset(nxt, 0, sizeof nxt);
memset(head, -1, sizeof head);
}
void init_table(ll g, ll p) { ///生成元,素数p
m = maxn; ll e = 1;
for(ll i = 0; i < m; i++) {
ll id = e % hash_size;
if(~head[id]) nxt[top] = head[id];
head[id] = top;
hash_table[top] = e; mp[top] = i;
e = e * g % p; top++;
}
gm = e; pri = p;
inv = exgcd(gm, p, 1);
}
ll query(ll x) {
for(ll i = 0; i <= pri / m; i++) {
ll id = x % hash_size;
ll hd = head[id];
if(~hd) for( ; hd; hd = nxt[hd]) {
if(hash_table[hd] == x) return i * m + mp[hd];
}
x = x * inv % pri;
}
return -1;
}
} hs;
ll qmod(ll x, ll n, ll mod) {
ll ans = 1;
while(n) {
if(n & 1) ans = ans * x % mod;
x = x * x % mod;
n >>= 1;
}
return ans;
}
void divide(ll x, vector<ll> &vec) { ///分解质因数
for(ll i = 0; prime[i] * prime[i] <= x; i++) {
ll t = prime[i];
if(x % t) continue;
vec.push_back(t);
while(x % t == 0) x /= t;
}
if(x != 1) vec.push_back(x);
}
void init() {
num = 0;
for(ll i = 2; i < maxn; i++) {
if(!prime[i]) prime[num++] = i;
else continue;
for(ll j = (ll)i * i; j < maxn; j += i) prime[j] = 1;
}
}
ll T, n, m, kase = 1, sum, q;
vector<ll> G;
ll find_g(ll p) {
if(p == 2) return 1;
vector<ll> vs; divide(p - 1, vs);
for(ll c = 2; ; c++) {
ll flag = 1;
for(ll j = 0; j < vs.size(); j++)
if(qmod(c, (p - 1) / vs[j], p) == 1) { flag = 0; break; }
if(flag) return c;
}
}
///小范围暴力,大的数最多只有一个
void init_hash() {
for(ll i = 0; i < G.size(); i++) {
ll c = G[i], g = find_g(c), ds = 1;
if(G[i] > 1e4) { hs.init(); hs.init_table(g, c); continue; }
for(int j = 0; j < c - 1; j++) {
res[i][ds] = j;
ds = ds * g % c;
}
}
}
ll solve(ll id, ll x, ll y, ll p) {
ll kx, ky;
if(p < 1e4) kx = res[id][x], ky = res[id][y];
else kx = hs.query(x), ky = hs.query(y);
if(kx == -1 || ky == -1) return INF;
ll ans = exgcd(kx, p - 1, ky);
if(ans == -1) return INF;
return ans;
}
int main() {
init();
scanf("%lld", &T);
while(T--) {
scanf("%lld %lld", &sum, &q);
G.clear(); divide(sum, G);
printf("Case #%lld:\n", kase++);
init_hash();
while(q--) {
ll x, y, ans = INF;
scanf("%lld %lld", &x, &y);
for(ll i = 0; i < G.size(); i++) {
ll p = G[i], xs = x % p, ys = y % p;
ans = min(ans, solve(i, xs, ys, p));
}
if(ans == INF) printf("-1\n");
else printf("%lld\n", ans);
}
}
return 0;
}
HDU5377 Root(扩展欧几里得 + 生成元)
最新推荐文章于 2020-01-10 16:30:58 发布