Codeforces 571E

100 篇文章 0 订阅
20 篇文章 0 订阅

首先将所有的 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,jk,其中 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 1in都有 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<jm,我们枚举 1 < i ≤ n 1<i\leq n 1<in,若有 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 1in y ≡ c i , 1 (   m o d   d i , 1 ) y\equiv c_{i,1} (\bmod d_{i,1}) yci,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;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值