题目链接:点击查看
题目大意:给出 a 和 b ,求解满足条件的 c,d,e,f ,使得:
- d < b
- f < b
- c,e 均为小于等于 4e12 的正整数
题目分析:分情况讨论一下,首先如果 a 和 b 可以约分的话,那么直接约分后,输出 a+1 , b , 1 , b 显然就是答案了,如果不能约分的话,且 b 的相异质因子的个数不超过 1 个的话,那么是无解的,证明如下:(来自官方题解)
最后一种情况就是 b 的相异质因子个数超过一个,对于这种情况可以将条件 1 的公式转换一下:
这样一来,d 和 f 显然就是 b 的两个相异质因子了,而 cf - de = a ,在已知 d 和 f 的前提下,一定有解,且可以用扩展欧几里得来解决,注意最后求出来的答案需要处理一下,因为需要保证 c 和 e 为正整数
在找 d 和 f 的时候也有技巧,如果 sqrt( n ) 暴力去找的话,会超时,所以可以用埃氏筛预处理一下,保存一下每个数字的最大质因子,这样就可以令 d 为该质因子的幂,然后 f = b / d 了
代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=2e6+100;
int pri[N];//pri[i]:i的最大质因子为pri[i]
template<class T> void exgcd(T a,T b,T &d,T &x,T &y){
if(!b) {d=a;x=1;y=0;}
else {exgcd(b,a%b,d,y,x);y-=x*(a/b);}
}
//求解二元一次方程 a*x+b*y=c,一组解为x,y,无解则返回false
template<class T> bool Solve_equation(T a,T b,T c,T &x,T& y){
T gcd;
exgcd(a,b,gcd,x,y);
if(c%gcd) return false; //无解
T k=c/gcd;
x*=k;y*=k;
T xplus=b/gcd,yplus=a/gcd;
if(xplus<0) xplus*=-1;if(yplus<0) yplus*=-1;
//此时求出的x,y即为一组解,该方程的通解形式为X=x+t*(b/gcd),Y=y-t*(a/gcd) t为任意正整数
//根据题目要求我们需要构造特殊解
//x=(x%xplus+xplus)%xplus;y=c-a*x; //x的最小正整数解
//y=(y%yplus+yplus)%yplus;x=c-b*y; //y的最小正整数解
return true;
}
void init()
{
pri[1]=1;
for(int i=2;i<N;i++)
if(!pri[i])//当前的数为质数
for(int j=i;j<N;j+=i)
pri[j]=i;
}
int main()
{
#ifndef ONLINE_JUDGE
// freopen("data.in.txt","r",stdin);
// freopen("data.out.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
init();
int w;
cin>>w;
while(w--)
{
LL a,b;
scanf("%lld%lld",&a,&b);
LL gcd=__gcd(a,b);
a/=gcd,b/=gcd;
if(gcd!=1)
{
printf("%lld %lld %lld %lld\n",a+1,b,1,b);
continue;
}
LL d=1,f=b;
while(pri[b]!=1&&f%pri[b]==0)
{
f/=pri[b];
d*=pri[b];
}
if(f==1)//只有一个质因子
{
printf("-1 -1 -1 -1\n");
continue;
}
LL c,e;
Solve_equation(f,-d,a,c,e);
LL k=abs(min(c/d,e/f))+1;
c+=d*k,e+=f*k;
printf("%lld %lld %lld %lld\n",c,d,e,f);
}
return 0;
}