2020 China Collegiate Programming Contest, Weihai Site D. ABC Conjecture(唯一分解定理/Pollard Rho)

ABC Conjecture Time limit: 3 seconds Figure 1: Shinichi Mochizuki The ABC conjecture (also known as the Oesterle–Masser conjec- ´ ture) is a famous conjecture in number theory, first proposed by Joseph Oesterle and David Masser. It is formally stated as follows: ´ For every positive real number ε, there are only finitely many positive integer triples (a, b, c) such that 1. a and b are relatively prime; 2. a + b = c; and 3. c > rad(abc) 1+ε , where rad(n) = Y p|n p∈Prime p is the product of all distinct prime divisors of n. Shinichi Mochizuki claimed to have proven this conjecture in August 2012. Later, Mochizuki’s claimed proof was announced to be published in Publications of the Research Institute for Mathematical Sciences (RIMS), a journal of which Mochizuki is the chief editor. Spike is a great fan of number theory and wanted to prove the ABC conjecture as well. However, due to his inability, he turned to work on a weaker version of the ABC conjecture, which is formally stated as follows: Given a positive integer c, determine if there exists positive integers a, b, such that a + b = c and rad(abc) < c. Note that in the original ABC conjecture, the positive integers a and b are required to be relatively prime. However, as Spike is solving an easier version of the problem, this requirement is removed. Input The first line of input contains one integer T (1 ≤ T ≤ 10), the number of test cases. The next lines contain description of the t test cases. Each test case contains one line, including an integer c (1 ≤ c ≤ 1018). Output For each test case, if there exist two positive integers a, b satisfying a + b = c and rad(abc) < c, then output yes in a line, otherwise output no instead.

Example

standard input

3

4

18

30

standard output

yes

yes

no

首先如果c是质数的话肯定不行,然后考虑把c唯一分解:(c = p_1^{x_1}p_2^{x_2}...p_k^{x_k})。考虑rad函数的性质,就会发现如果每个质数的次数都为1肯定也不行,因为此时rad(c) = c,rad(abc)大于等于c,不满足要求。那么c的某个质因子的次数至少为2,设(c = p_1^{2}x),则可以令(a = p_1x,b=(1-p_1)p_1x),则(rad(abc) = rad(p_1x(1-p_1)p_1xp_1x)=rad((1-p_1)p_1x)),又因为((1-p_1)p_1x < {p_1}^2x = c),因此 (rad((1-p_1)p_1x) < c)。故此时直接输出yes即可。

由于范围到了1e18,因此需要用Pollard Rho进行大数唯一分解。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5+16;
LL n, x,y,a[maxn];
struct BigIntegerFactor{
    const static int maxm = 1e6+16;
    LL prime[maxm],p[maxm],fac[maxm],sz,cnt;     //多组输入注意初始化cnt = 0
    inline LL mul(LL a,LL b,LL mod){             //WA了尝试改为__int128或慢速乘
        if(mod <= 1000000000) return a * b % mod;
        return (a*b-(LL)((long double)a/mod*b+1e-8)*mod+mod)%mod;
    }
    void init(int maxn){
        int tot = 0; sz = maxn-1;
        for(int i = 1;i <= sz; ++i) p[i] = i;
        for(int i = 2;i <= sz; ++i){
            if(p[i] == i) prime[tot++] = i;
            for(int j = 0;j<tot&&1ll*i*prime[j]<=sz; ++j){
                p[i*prime[j]] = prime[j];
                if(i%prime[j] == 0) break;
            }
        }
    }
    LL powl(LL a,LL x,LL mod){
        LL res = 1LL;
        while(x){
            if(x&1) res = mul(res,a,mod);
            a = mul(a,a,mod);
            x >>= 1;
        }
        return res;
    }
    bool check(LL a,LL n){                       //二次探测原理检验n
        LL t = 0,u = n-1;
        while(!(u&1)) t++,u >>= 1;
        LL x = powl(a,u,n),xx = 0;
        while(t--){
            xx = mul(x,x,n);
            if(xx==1 && x!=1 && x!=n-1) return false;
            x = xx;
        }
        return xx == 1;
    }
    bool miller(LL n,int k){
        if(n == 2) return true;
        if(n < 2 || !(n&1)) return false;
        if(n <= sz) return p[n] == n;
        for(int i = 0;i <= k; ++i){               //测试k次
            if(!check(rand()%(n-1)+1,n)) return false;
        }
        return true;
    }
    inline LL gcd(LL a,LL b){
        return b == 0 ? a : gcd(b,a%b);
    }
    inline LL Abs(LL x){
        return x < 0 ? -x : x;
    }
    LL Pollard_rho(LL n){                  //基于路径倍增的Pollard_Rho算法
        LL s = 0,t = 0,c = rand()%(n-1)+1,v = 1,ed = 1;
        while(1){
            for(int i = 1; i <= ed; ++i){
                t = (mul(t,t,n) + c) % n; v = mul(v,Abs(t-s),n);
                if(i % 127 == 0){
                    LL d = gcd(v,n);
                    if(d > 1) return d;
                }
            }
            LL d = gcd(v,n); if(d > 1) return d;
            s = t; v = 1; ed <<= 1;           
        }
    }
    void getfactor(LL n){                          //得到所有的质因子(可能有重复的)
        if(n <= sz){
            while(n != 1) fac[cnt++] = p[n],n /= p[n];
            return;
        }
        if(miller(n,6)) fac[cnt++] = n;
        else{
            LL d = n; while(d >= n) d = Pollard_rho(n);
            getfactor(d); getfactor(n/d);
        }
    }
    LL cal(LL n,LL x){                            //计算 n! 中质因子 x 的数量
        LL num = 0;
        while(n){
            num += n/x;
            n = n/x;
        }
        return num;
    }
    bool judge(LL x) {
        //cnt = 0; getfactor(x);
        //因为必定先判断素数 这时候的cnt已经计算出来了 因此这里不用再计算一遍 也无需再清空
        map<LL, LL> mp;
        for(int i = 0;i < cnt; ++i) {
            if(mp.find(fac[i]) != mp.end()) return 0;
            mp[fac[i]]++;
        }
        return 1;
    }
    bool isPrime(LL x) {
        cnt = 0; getfactor(x);
        if(cnt == 1) return 1;
        else return 0;
    }
}Q;

int main() {
	int t;
	cin >> t;
    Q.init(200000);
	while(t--) {
		long long c;
        scanf("%lld", &c);
        if(Q.isPrime(c)) {
            cout << "no" << endl;
        } else {
            bool allone = Q.judge(c);//判断c的所有质因子的次数是否都为1
            if(allone) cout << "no" << endl;
            else {
                cout << "yes" << endl;
            }
        }
		
	}
	return 0;
}
原文地址:https://www.cnblogs.com/lipoicyclic/p/14756404.html