1. 程式人生 > >Weakened Common Divisor(cf div1+div2 B)

Weakened Common Divisor(cf div1+div2 B)

題目連結:

B. Weakened Common Divisor

 

題意:

給定n對數,求一個WCD,它滿足至少能被每對數中的一個整除,若不存在,輸出-1。

 

思路:

一開始的思路是求每對數的最小公倍數,然後把這n個最小公倍數求個gcd,然後取其最小因子即可。但這樣因為TLE而FST了。後來想想也是,如果每對數中的兩個數互質,那麼他們的最小公倍數就是1e18左右的大小,求其最小因子的時間複雜度差不多就是1e9,肯定會T。比如下面這組樣例:

2
1999999973 1999999943
1999999973 1999999943

其實正解想法差不多,就把第一對中的第一個數和後面每對的乘積求一個gcd,第二個數也和後面的每對的乘積求一個gcd,這樣就保證這兩個數都是小於等於2e9的,求其最小因子的複雜度<1e5,可行。

PS:其實並不需要求每對數的最小公倍數,求其乘積即可,因為乘積包括了每對數那2個數中的所有因子,且乘積的最小因子一定能被每對數那2個數中的1個整除。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <set>
#include <queue>
#include <algorithm>
using namespace std;

typedef long long ll;

const int MAX = 150000 + 10;
const ll mod = 1e9 + 7;

int n;

ll gcd(ll m, ll n)
{
    while (m>0)
    {
	ll c = n % m;
	n = m;
	m = c;
    }
    return n;
}

inline ll read() {
    char ch = getchar(); ll x = 0, f = 1;
    while(ch < '0' || ch > '9') {
        if(ch == '-') f = -1;
        ch = getchar();
    } while('0' <= ch && ch <= '9') {
        x = x * 10 + ch - '0';
        ch = getchar();
    } return x * f;
}

ll solve(ll x)
{
    for (ll i = 2; i*i <= x; i++) {
        if (x%i == 0) {
            return i;
        }
    }
    return x;
}

int main()
{
	n=read();
	ll a, b;
	a=read();
	b=read();
	if (n == 1) {
		printf("%lld\n", a);
		return 0;
	}
	int cnt=0;
	ll ans1,ans2;
	ans1=a; ans2=b;
	for (int i = 1; i < n; i++) {
	    ll x, y;
	    x=read();
	    y=read();
	    ll g = x*y;
	    ans1 = gcd(ans1, g);
	    ans2 = gcd(ans2, g);
	}
	if(ans1!=1){
            ll ans=solve(ans1);
            printf("%lld\n",ans);
	}
	else if(ans2!=1){
            ll ans=solve(ans2);
            printf("%lld\n",ans);
	}
	else{
            printf("-1\n");
	}
	return 0;
}