题意:给定你一个数c(c < 1e18),问你能否找到一个a和b使得 a + b = c,并且使得他们的乘积 a * b * c的所有不同的素因子的乘积小于c。
思路:给定一个c,我们先把c做质因数分解,然后从他的质因数中选中部分质因数或者他们的幂次构成a,然后我们考虑如何让c-a的质因子能最大程度的尽量和他们相同。
也就是说假如给定c = p1^x1 * p2x2 * p3^ x3 …pn ^ xm,我们如果选择a = p1^x1 * p2^x2 * p3^ x3 …pn ^ (xm-1),那么我们就可以知道b就应该 = p1^x1 * p2x2 * p3^ x3 …pn^(xm-1) * (xm-1),我们可以看到 无论如何 这个xm-1对乘积的贡献一定是比xm小的,所以即使这样选择多abc多出了一个xm-1大小的因子,但是他一定不会使得p1 * p2 * …pn*(xm-1)这个值大于c。
所以我们可以得到结论对于给定的c加入他是个素数,那么a和b是一定找不出来的,如果不是个素数,我们对c进行质因数分解,假如的它有任意至少一个质因子的幂次大于1,那么对于这样的c,a和b是可以找到的,否则也是找不到。
然后对1在特判一下即可。
代码:
/*---------------------------------------------
POJ 1811
最后更新:2019/8/11
说明:该代码包含了取随机值函数rand()以及求最小值函数min()
注:适用范围是2^61,至少要保证中间结果不会溢出long long
(中间结果最多是2*n)
----------------------------------------------*/
#include <bits/stdc++.h>
typedef long long ll;
/*---------------------------------------------
利用 Miller-Rabin进行素性测试
----------------------------------------------*/
int testnum[] = {2,7,61,3,5,11,13,19};
ll fmul(ll a,ll b,ll p){
/*返回a * b % p*/
a %= p,b %= p; //防止超出精度
ll res = 0;
while(b){
if(b&1) res += a, res %= p;
a <<= 1; //a = a*2
if(a >= p) a %= p;
b >>= 1; //b = b/2
}
return res;
}
ll qpow(ll a,ll b,ll p){
/*返回a^b % p*/
ll res = 1;
while(b){
if(b&1) res = fmul(res,a,p);
a = fmul(a,a,p);
b >>= 1;
}
return res;
}
bool isPrime(ll n){
/*Miller-Rabin判定x是否为素数*/
if(n == 2) return true;
if(n < 2 || n%2 == 0) return false;
ll d = n-1, a, x, y;int t = 0;
while((d&1) == 0) d >>= 1,t++;
for(int i = 0;i < 7;i++){
a = testnum[i];
if(n == a) return true;
x = qpow(a,d,n);
for(int j = 0;j < t;j++){
y = fmul(x,x,n);
if(y == 1 && x != 1 && x != n-1) return false;
x = y;
}
if(x != 1) return false;
}
return true;
}
/*---------------------------------------------
利用 pollard rho 算法进行质因数分解
----------------------------------------------*/
ll factors[110]; //用来存放被分解的因数(无序)
int tot = 0; //因子个数
ll gcd(ll a,ll b){
/* 返回a和b的最大公约数 */
if(a == 0) return 1;
if(a < 0) return gcd(-a,b);
while(b){
ll t = a%b;
a = b; b = t;
}
return a;
}
ll pollard_rho(ll x,ll c){
/* 返回 x 的一个因子或 x 本身 */
ll i = 1,k = 2;
ll tx = rand()%x;
ll y = tx;
while(true){
i++;
tx = (fmul(tx,tx,x)+c)%x;
ll d = gcd(y-tx,x);
if(d != 1 && d != x) return d;
if(y == tx) return x; //寻找失败
if(i == k) y = tx, k += k;
}
}
void findFac(ll n){
/* 对 n 进行质因数分解 */
if(isPrime(n)){
factors[++tot] = n;
return ;
}
ll p = n;
/* 通过pollard_rho算法找到 n 的一个因子 p */
while(p >= n) p = pollard_rho(p,rand()%(n-1)+1);
findFac(p); //递归分解
findFac(n/p);
}
std::set<ll>ss;
int main(){
int t;ll n,ans;
scanf("%d",&t);
while(t--){
scanf("%lld",&n);
if(n == 1){ printf("no\n");continue; }
else if(isPrime(n)) puts("no");
else{
tot = 0; ans = 1e18;
int flag = 0;
findFac(n);
ss.clear();
for(int i = 1;i <= tot;i++){
if(ss.count(factors[i])){ flag = 1;break; }
else ss.insert(factors[i]);
}
if(flag) puts("yes");
else puts("no");
}
}
return 0;
}