2020CCPC 威海站 D ABC Conjecture(数论)
题意 :给一个数 C(1-1e18),要求找到一个a,b。a+b=c;然后abc的积里面的素数因子要求< c,如果可以找到那么答案yes,否者no。
题解:首先可以明确的发现如果C是素数,一定是no,因为 a,b里面必然还有别的素因子,那么相乘必然大于c,所以现在就是判断合数,那么怎么样合数满足条件,C=A * B * C * D * E…;我们可以把C这样表示出来,然后要尽量去减少他的因数的贡献是不是他的因子里面就要有幂次的,这样子 他的贡献会产生到最小,然后a,b我们就根据素数因子来构造a+b=c;这样子一个可以使得贡献最小,列入 30 =5 * 2 * 3;我们无论怎么构造 a,b是不是都不可以减少贡献,因为C的贡献已经超过C本身了,那么如果是60=5 * 3 * 2 * 2;a=30,b=30;30=5 * 2 * 3; 最后的贡献是不是就变成30了,所以素数的枚举已经因子的幂次很重要 ,当大于2次幂的就会满足条件,最后我是枚举了1e7的素数,然后每次去判断是否有幂次的,如果1e7的素数找不到他的素数因子 ,那么该数必然是素数,或者素数因子大于1e7的范围,那么我们在前面处理的时候就先把他的素数单因子处理掉 ,最后在sqrt一下看看是不是能够开方,然后判断就好啦
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define fio ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define mse(a,b) memset(a,b,sizeof a)
#define pb push_back
using namespace std;
const int mod=1e9+7;
const int maxx=1e7+10;
using namespace std;
const long double PI = 3.14159265358979323846;
//inline int read(){ int x=0,f=1; char ch=getchar(); while (!isdigit(ch)) { if (ch=='-') f=-1; ch=getchar(); } while (isdigit(ch)) { x=x*10+ch-48; ch=getchar(); } return x*f;}
// ll cc = ((1ll << 62) - 1 + (1ll << 62));
int vis[maxx];
int cnt=0;
int prime[maxx];
void pri()
{
for(int i=2;i<=1e7;i++)
{
if(!vis[i]) prime[++cnt]=i;
for(int j=1;j<=cnt&&prime[j]*i<1e7;j++)
{
vis[i*prime[j]]=1;
if(i%prime[j]==0) break;
}
}
}
signed main()
{
pri();
int t;
cin>>t;
while(t--){
ll n;
cin>>n;
bool flag=false;
for(int i=1;i<=cnt&&n>=i*i;i++)
{
if(n%(prime[i]*prime[i])==0)
{
flag=true;
break;
}
if(n%prime[i]==0)
n/=prime[i];
}
if(flag) cout<<"yes"<<endl;
else if(n>1){
ll ans=sqrt(n);
if(ans*ans==n) cout<<"yes"<<endl;
else cout<<"no"<<endl;
}
else cout<<"no"<<endl;
}
return 0;
}