给出一个数字m,求满足m = a^3 + b^3(a,b为正整数)的所有整数对(分解素因子防超时)

题目连接:ZOJ-3673

题目大意:给出一个数字m,求满足m = a^3 + b^3(a,b为正整数)的所有整数对。

题目思路:

已知 m = a3+b3=(a+b)(a2ab+b2)  ①

设 t = a + b; 

②代入①,因为 m =  (a+b)((a+b)23ab)

可得,n =  ab=(t2m/t)/3

–> a2+at+n=0 ; 求出a可得b

关键求m的约数即为(a+b)(以上from my son loy)

#include<bits/stdc++.h>
#define ll unsigned long long
#define maxn 2642246*2 //n=a^3+b^3=(a+b)(a^2-ab+b^2),a和b都不大于3√(2^64)=2642245 
using namespace std;
struct node{
	int a,b; //n所含素因子和个数 
}x[maxn+2];
int noprime[maxn+2];
vector<int> isprime;
vector<pair<int,int> > ans;
ll n; 
int c;
map<int,int> r;
void gao(ll t){ //t=a+b
	if((t*t-n/t)%3!=0) return;
	ll m=(t*t-n/t)/3; //n=a^3+b^3=(a+b)(a^2-ab+b^2)=(a+b)((a+b)^3-3ab),m=a*b=(t^2-n/t)/3
	ll delta=t*t-4*m; //由a+b=t和a*b=m 得出 a^2-t*a+m=0 
	if(delta<0) return;
	double a=(t+sqrt(delta))/2.0;
	if(a>=t) return; //是否有一个≤0 
	if(a-(ll)a==0&&r[min(a,t-a)]==0){
		r[min(a,t-a)]=1;
		ans.push_back({min(a,t-a),max(a,t-a)});
	}
}
void dfs(int p,ll s){
	if(s>1&&s<=maxn)
		gao(s);
	if(p>c)
		return;
	ll ss=1;
	for(int i=0;i<=x[p].b;++i){
		dfs(p+1,s*ss);
		ss*=x[p].a;
	}
}
int main(){
	for(int i=2;i<=maxn;++i){
		if(noprime[i]==0){
			isprime.push_back(i);
			for(int j=i*2;j<=maxn;j+=i){
				noprime[j]=1;
			}
		}
	}
	while(~scanf("%llu",&n)){
		r.clear();
		ans.clear();
		ll tmp=n;
		c=-1;
		for(int i=0;i<isprime.size();++i){ //这里预处理素数可以防止超时,学习
			if(n%isprime[i]==0){
				int s=0;
				while(n%isprime[i]==0){
					s++;
					n/=isprime[i];
				}
				x[++c].a=isprime[i];
				x[c].b=s;
			}
			if(n==1)
				break;  //这句必须要加,否则超时!!! 
		} 
		if(n>1){
			x[++c].a=n;
			x[c].b=1;
		}
		n=tmp;
		dfs(0,1);
		sort(ans.begin(),ans.end());
		printf("%d",ans.size());
		for(int i=0;i<ans.size();i++){
            printf(" (%llu,%llu)",ans[i].first,ans[i].second);
        }
        printf("\n");
	}
	return 0;
}

之所以要分解素因子的原因在于,下面这个代码是会超时的:

#include<bits/stdc++.h>  
#define ll unsigned long long  
#define maxn (ll)2642246 //n=a^3+b^3=(a+b)(a^2-ab+b^2),a和b都不大于3√(2^64)=2642245   
using namespace std;  
vector<pair<int,int> > v;  
map<ll,int> r;  
int main(){  
    ll n;  
    while(scanf("%llu",&n)!=EOF){ 
        v.clear();  
        r.clear();  
        for(ll t=2;t<=min((ll)pow(n,1.0/3)*2,maxn);++t){ //直接遍历所有t的可能值  
            if((t*t-n/t)%3!=0) continue;
		    ll m=(t*t-n/t)/3; //n=a^3+b^3=(a+b)(a^2-ab+b^2)=(a+b)((a+b)^3-3ab),m=a*b=(t^2-n/t)/3  
		    ll delta=t*t-4*m; //由a+b=t和a*b=m 得出 a^2-t*a+m=0   
		    if(delta<0) continue;  
		    double a=(t+sqrt(delta))/2.0;  
		    if(a>=t) continue; //是否有一个≤0   
		    if(a-(ll)a==0&&r[min(a,t-a)]==0){  
		        r[min(a,t-a)]=1;  
		        v.push_back({min(a,t-a),max(a,t-a)});  
		    }  
        }  
        sort(v.begin(),v.end());  
        printf("%d",v.size());  
        for(int i=0;i<v.size();++i)  
            printf(" (%d,%d)",v[i].first,v[i].second);  
        printf("\n");  
    }  
    return 0;  
}  
其实自己觉得两个复杂度差不多,第一个代码isprime.size()也有3w多,为什么超时我也不知道了。也许是卡在大数据多(一个3w多,一个20w多)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值