首先将所有的 a i a_i ai, b i b_i bi均分解质因数,由于 n n n较小,采用根号试除法即可。
假设所有的等比数列共有 m m m个不同的质因子,从小到大依次为 p 1 p_1 p1, p 2 p_2 p2, . . . ... ..., p m p_m pm。于是我们可以知道第 i i i个等比数列的第 k k k项为 ∏ j = 1 m p j c i , j + d i , j ⋅ k \prod_{j=1}^{m}p_j^{c_{i,j}+d_{i,j}\cdot k} ∏j=1mpjci,j+di,j⋅k,其中 c i , j c_{i,j} ci,j是 a i a_i ai中 p j p_j pj的指数, d i , j d_{i,j} di,j是 b i b_i bi中 p j p_j pj的幂次。
若 ∃ j \exist j ∃j,使得 ∃ u \exist u ∃u有 d u , j = 0 d_{u,j}=0 du,j=0。我们发现当 ∀ 1 ≤ i ≤ n \forall 1\leq i\leq n ∀1≤i≤n都有 d i , j = 0 d_{i,j}=0 di,j=0时,显然当 c i , j c_{i,j} ci,j均相等时可以忽略掉这个质因子(最后答案乘上即可),否则直接无解。若 ∃ v \exist v ∃v有 d v , j > 0 d_{v,j}>0 dv,j>0,那么合法的 x x x至多只有一个,直接尝试解出来判定是否合法即可。
经过上面的处理后,我们可以认为所有的 d i , j d_{i,j} di,j均不为 0 0 0。此时如果仍有 m > 1 m>1 m>1,我们尝试消到只剩一个质因子,具体是对于某个 1 < j ≤ m 1<j\leq m 1<j≤m,我们枚举 1 < i ≤ n 1<i\leq n 1<i≤n,若有 d 1 , 1 d i , 1 ≠ d 1 , j d i , j \frac{d_{1,1}}{d_{i,1}}\neq \frac{d_{1,j}}{d_{i,j}} di,1d1,1=di,jd1,j,那么同样合法的 x x x至多只有一个,尝试解出来判定是否合法即可,否则先看 c i , j c_{i,j} ci,j是否成比例,如果不成比例也无解,成的话就可以忽略掉 p j p_j pj了。
这样我们终于转化为了只有一个质因子 p 1 p_1 p1的情况,那么我们设最终 x x x中 p 1 p_1 p1的幂次为 y y y,显然有 ∀ 1 ≤ i ≤ n \forall 1\leq i\leq n ∀1≤i≤n, y ≡ c i , 1 ( m o d d i , 1 ) y\equiv c_{i,1} (\bmod d_{i,1}) y≡ci,1(moddi,1)。这样问题转化为了给出 n n n个线性同余方程,要求出最小的非负整数解。这个问题有经典的扩展CRT做法,即每次尝试合并两个同余方程(可能无解)。求出了最小的 y y y后就容易求出答案了。
注意有一个坑点,刚刚的同余方程其实忽略了一些信息,有可能这样求出来的最小的 y y y会比某个 c i , 1 c_{i,1} ci,1小,因此需要加上 l c m i = 1 n d i , 1 lcm_{i=1}^{n}d_{i,1} lcmi=1ndi,1的倍数。
时间复杂度是 O ( n ( V + m ) ) \mathcal O(n(\sqrt{V}+m)) O(n(V+m))。
#include <bits/stdc++.h>
#define MOD 1000000007
using namespace std;
typedef long long ll;
inline ll lcm(ll x,ll y) {
return x/__gcd(x,y)*y;
}
ll pow_mod(ll x,ll k) {
ll ans=1;
while (k) {
if (k&1) ans=ans*x%MOD;
x=x*x%MOD;
k>>=1;
}
return ans;
}
void exgcd(ll a,ll b,ll &x,ll &y) {
if (!b) {
x=1;y=0;
}
else {
exgcd(b,a%b,y,x);
y-=(a/b)*x;
}
}
ll getinv(ll x,ll mod) {
ll t1,t2;
exgcd(x,mod,t1,t2);
return (t1%mod+mod)%mod;
}
map <int,int> mp;
int prime[2005],cnt;
bool vis[2005];
int a[105][2005],b[105][2005];
void check_sol(int n,int x,ll d) {
int ans=1;
for(int i=1;i<=cnt;i++) {
ll v=a[x][i]+b[x][i]*d;
for(int j=1;j<=n;j++)
if (b[j][i]) {
if (v<a[j][i]||(v-a[j][i])%b[j][i]!=0) return;
}
else if (a[j][i]!=v) return;
ans=ans*pow_mod(prime[i],v)%MOD;
}
printf("%d\n",ans);
exit(0);
}
bool check(int n) {
for(int i=1;i<=cnt;i++) {
int id=0;
for(int j=1;j<=n;j++)
if (!b[j][i]) id=j;
if (!id) continue;
vis[i]=1;
for(int j=1;j<=n;j++)
if (b[j][i]) {
int v=a[id][i]-a[j][i];
if (v%b[j][i]!=0) return 0;
v/=b[j][i];
if (v<0) return 0;
check_sol(n,j,v);
return 0;
}
else if (a[j][i]!=a[id][i]) return 0;
}
int id=1;
while (id<=cnt&&vis[id]) id++;
if (id>cnt) check_sol(n,1,0);
for(int i=id+1;i<=cnt;i++)
if (!vis[i]) {
for(int j=2;j<=n;j++) {
int u=a[j][id]-a[1][id],v=a[j][i]-a[1][i];
if (b[1][id]*b[j][i]!=b[1][i]*b[j][id]) {
int t1=b[1][id]*b[j][i]-b[1][i]*b[j][id],t2=u*b[j][i]-v*b[j][id];
if (t2%t1!=0) return 0;
t2/=t1;
if (t2<0) return 0;
check_sol(n,1,t2);
}
else if (b[1][id]*v!=b[1][i]*u) return 0;
}
}
return 1;
}
bool solve(int n) {
int id=1;
while (id<=cnt&&vis[id]) id++;
ll s=a[1][id]%b[1][id],w=b[1][id];
for(int i=2;i<=n;i++) {
ll u=a[i][id]%b[i][id],v=b[i][id];
ll d=__gcd(w,v);
if ((u-s)%d!=0) return 0;
ll ww=w/d,vv=v/d,cc=(u-s)/d;
ll x=(getinv(ww,vv)*cc%vv+vv)%vv;
s=w*x+s;w=lcm(w,v);
}
for(int i=1;i<=n;i++) {
while (s<a[i][id]) s+=w;
}
check_sol(n,1,(s-a[1][id])/b[1][id]);
}
void getfact(int x,int *p) {
int t=x;
for(int i=2;i*i<=t;i++)
if (x%i==0) {
if (!mp.count(i)) {
mp[i]=++cnt;
prime[cnt]=i;
}
int u=mp[i];
while (x%i==0) {
p[u]++;
x/=i;
}
}
if (x>1) {
if (!mp.count(x)) {
mp[x]=++cnt;
prime[cnt]=x;
}
int u=mp[x];
p[u]=1;
}
}
int main() {
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) {
int x,y;
scanf("%d%d",&x,&y);
getfact(x,a[i]);
getfact(y,b[i]);
}
if (!check(n)) {
puts("-1");
return 0;
}
if (!solve(n)) {
puts("-1");
return 0;
}
return 0;
}