题解 [CF571E] Geometric Progressions
为啥我一看到 exCRT 就会觉得十分不可写并进行一个路的跑啊(
先来康康一个等比数列中的数会有什么性质
若进行一个质因数分解
\[a=\prod p_i^{s_i}
\]
\[b=\prod p_i^{t_i}
\]
那么等比数列中的数就是
\[\prod p_i^{s_i+t_ik_i}, k_i\geqslant 0
\]
那么尝试联立两个数列的这个方程组
若无解那么就无解
若有解就带进去 check 一下
若无穷解当且仅当每个数都仅有同一个质因子或每个质因子 \(s, t\) 均成比例
这个试着解一解方程就可以得到
要求 \(s\) 也成比例可以通过原形方程得到
然后问题变成了求一个最小的 \(y\) 使得
\[\begin{cases} y \equiv s_1 \pmod {t_1}\\ y \equiv s_2 \pmod {t_2}\\ \cdots \end{cases}
\]
那么 excrt 解就行了
细节非常多,包括但不限于
解出来的是 \(y\bmod{\mathrm{lcm}}\),所以还要给 \(y\) 加 \(\mathrm{lcm}\) 直到所有 \(k\) 都非负为止
可能存在一些只存在于所有分子中而不存在于任何一个分母中的质因子,这种质因子不能用来当模数
复杂度 \(O(n^2\sqrt V\log V)\)
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 300010
#define fir first
#define sec second
#define ll long long
#define int128 __int128
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n;
ll a[N], b[N];
const ll mod=1e9+7;
inline ll qpow(ll a, ll b) {ll ans=1; for (; b; a=a*a%mod,b>>=1) if (b&1) ans=ans*a%mod; return ans;}
namespace force{
__int128 val[N];
map<__int128, int> mp;
set<__int128> s;
void solve() {
for (int i=1; i<=n; ++i) {
s.clear();
s.insert(val[0]=a[i]);
for (int j=1; j<=10; ++j) s.insert(val[j]=val[j-1]*b[i]);
for (auto it:s) ++mp[it];
}
for (auto it:mp) if (it.second==n) {cout<<(ll)(it.first%mod)<<endl; exit(0);}
}
}
namespace force2{
ll val[N];
map<ll, int> mp;
set<ll> s;
const ll mod=1e9+7;
void solve() {
for (int i=1; i<=n; ++i) {
s.clear();
s.insert(val[0]=a[i]%mod);
for (int j=1; j<=1000; ++j) s.insert(val[j]=val[j-1]*b[i]%mod);
for (auto it:s) ++mp[it];
}
for (auto it:mp) if (it.second==n) {cout<<(ll)(it.first%mod)<<endl; exit(0);}
}
}
namespace task1{
int dcnt, usiz;
pair<ll, ll> div[N];
ll *s[N], *t[N], r[N];
ll uni[N], k[N], val[N];
inline int128 gcd(int128 a, int128 b) {return !b?a:gcd(b, a%b);}
void check(int x) {for (int i=1; i<=usiz; ++i) if (s[x][i]+t[x][i]*k[x]!=val[i]) {puts("-1"); exit(0);}}
inline void exgcd(int128 a, int128 b, int128& x, int128& y) {
if (!b) {x=1; y=0; return ;}
exgcd(b, a%b, y, x);
y-=a/b*x;
}
void solve(int x) {
if (k[x]<0) {puts("-1"); exit(0);}
// cout<<"solve: "<<x<<" and k[x]="<<k[x]<<endl;
for (int i=1; i<=usiz; ++i) val[i]=s[x][i]+t[x][i]*k[x];
// cout<<"---s---"<<endl; for (int i=1; i<=n; ++i) {for (int j=1; j<=usiz; ++j) cout<<s[i][j]<<' '; cout<<endl;}
// cout<<"---t---"<<endl; for (int i=1; i<=n; ++i) {for (int j=1; j<=usiz; ++j) cout<<t[i][j]<<' '; cout<<endl;}
// cout<<"val: "; for (int i=1; i<=usiz; ++i) cout<<val[i]<<' '; cout<<endl;
for (int i=1; i<=n; ++i) if (i!=x) {
for (int j=1; j<=usiz; ++j) {
// cout<<"j: "<<j<<endl;
if (t[i][j]) {
// cout<<"check: "<<val[j]<<' '<<s[i][j]<<' '<<t[i][j]<<' '<<(val[j]-s[i][j])%t[i][j]<<endl;
if (!((val[j]-s[i][j])%t[i][j])) {
k[i]=(val[j]-s[i][j])/t[i][j];
if (k[i]<0) {puts("-1"); exit(0);}
check(i);
}
else {puts("-1"); exit(0);}
}
else if (s[i][j]!=val[j]) {puts("-1"); exit(0);}
}
}
ll ans=1;
for (int i=1; i<=usiz; ++i) ans=ans*qpow(uni[i], s[x][i]+t[x][i]*k[x])%mod;
printf("%lld\n", ans);
exit(0);
}
void divide(ll n) {
ll m=n; dcnt=0;
for (ll i=2; i*i<=n; ++i) if (!(m%i)) {
div[++dcnt]={i, 0};
do {m/=i; ++div[dcnt].sec;} while (!(m%i));
}
if (m>1) div[++dcnt]={m, 1};
}
void solve() {
for (int i=1; i<=n; ++i) {
divide(a[i]);
for (int j=1; j<=dcnt; ++j) uni[++usiz]=div[j].fir;
divide(b[i]);
for (int j=1; j<=dcnt; ++j) uni[++usiz]=div[j].fir;
}
sort(uni+1, uni+usiz+1);
usiz=unique(uni+1, uni+usiz+1)-uni-1;
for (int i=0; i<=n; ++i) {
s[i]=new ll[usiz+10]; t[i]=new ll[usiz+10];
for (int j=0; j<=usiz; ++j) s[i][j]=t[i][j]=0;
}
for (int i=1; i<=n; ++i) {
for (int j=1; j<=usiz; ++j) {
for (int now=a[i]; !(now%uni[j]); now/=uni[j],++s[i][j]);
for (int now=b[i]; !(now%uni[j]); now/=uni[j],++t[i][j]);
}
if (!s[i]&&!t[i]) {puts("-1"); exit(0);}
}
for (int i=1; i<=n; ++i) {
for (int j=i+1; j<=n; ++j) {
// cout<<"ij: "<<i<<' '<<j<<endl;
bool lst=0;
ll si, ti, sj, tj;
for (int l=1; l<=usiz; ++l) {
// cout<<"l: "<<l<<endl;
if (t[i][l]&&!t[j][l]) {
// cout<<"case 1"<<endl;
if ((s[j][l]-s[i][l])%t[i][l]) {puts("-1"); exit(0);}
else k[i]=(s[j][l]-s[i][l])/t[i][l], solve(i);
}
if (!t[i][l]&&t[j][l]) {
// cout<<"case 2"<<endl;
if ((s[i][l]-s[j][l])%t[j][l]) {puts("-1"); exit(0);}
else k[j]=(s[i][l]-s[j][l])/t[j][l], solve(j);
}
if (t[i][l]&&t[j][l]) {
// cout<<"case 3"<<endl;
if (lst) {
if (tj*t[i][l]-ti*t[j][l]) {
ll tem1=ti*s[j][l]-s[i][l]*ti-sj*t[j][l]+si*t[i][l];
ll tem2=tj*t[i][l]-ti*t[j][l];
if (tem1%tem2) {puts("-1"); exit(0);}
else {
k[j]=tem1/tem2;
solve(j);
}
}
else if (si*s[j][l]-s[i][l]*sj) {puts("-1"); exit(0);}
}
else si=s[i][l], ti=t[i][l], sj=s[j][l], tj=t[j][l], lst=1;
}
}
}
}
bool all_same=1; ll lst=a[1];
for (int i=1; i<=n; ++i) if (a[i]!=lst) goto jump;
printf("%lld\n", lst); exit(0);
jump: ;
// ll maxn=0;
// for (int i=1; i<=n; ++i) maxn=max(maxn, max(a[i], b[i]));
// if (maxn<=10) force::solve();
// force2::solve();
bool any_zero=0; ll val;
for (int i=1; i<=n; ++i) if (b[i]==1) {
if (any_zero&&val!=a[i]) {puts("-1"); exit(0);}
else any_zero=1, val=a[i];
}
int id=1;
for (; id<=usiz; ++id) {
bool all_zero=1;
for (int i=1; i<=n; ++i) if (t[i][id]) all_zero=0;
if (!all_zero) break;
}
if (id>usiz) {puts("-1"); exit(0);}
// cout<<"s: "; for (int i=1; i<=n; ++i) cout<<s[i][1]<<' '; cout<<endl;
// cout<<"t: "; for (int i=1; i<=n; ++i) cout<<t[i][1]<<' '; cout<<endl;
for (int i=1; i<=n; ++i) assert(t[i][id]);
for (int i=1; i<=n; ++i) r[i]=s[i][id]%t[i][id];
// cout<<"r: "; for (int i=1; i<=n; ++i) cout<<r[i]<<' '; cout<<endl;
// cout<<"m: "; for (int i=1; i<=n; ++i) cout<<t[i][1]<<' '; cout<<endl;
if (any_zero) {printf("%lld\n", val); exit(0);}
int128 rest=r[1], lcm=t[1][id];
for (int i=2; i<=n; ++i) {
// cout<<"i: "<<i<<endl;
int128 x1, x2, g=gcd(lcm, t[i][id]);
exgcd(lcm, t[i][id], x1, x2);
if ((r[i]-rest)%g) {puts("-1"); exit(0);}
x1=x1*((r[i]-rest)/g);
rest=rest+x1*lcm;
lcm=lcm/gcd(lcm, t[i][id])*t[i][id];
rest=(rest%lcm+lcm)%lcm;
}
// cout<<"rest: "<<(ll)rest<<endl;
for (int i=1; i<=n; ++i) if (rest<s[i][id]) rest+=((s[i][id]-rest-1)/lcm+1)*lcm;
// cout<<"rest: "<<(ll)rest<<endl;
k[1]=(rest-s[1][id])/t[1][id];
solve(1);
}
}
signed main()
{
// freopen("a.in", "r", stdin);
// freopen("a.out", "w", stdout);
n=read();
for (int i=1; i<=n; ++i) a[i]=read(), b[i]=read();
if (n==1) printf("%lld\n", a[1]);
else task1::solve();
return 0;
}