原题题面
有T个输入。
每组输入给出两个正整数
。
请找到四个正整数
,使他们满足:
如果有多组数据,输出其中一组。如果不存在,输出“-1 -1 -1 -1”。
输入样例
3
4 1
1 6
37 111
输出样例
-1 -1 -1 -1
1 2 1 3
145 87 104 78
题面分析
首先显然,当
不为1时,我们可以令
。构造
所以输出"a’+1 b’ 1 b’"即可。
当
时,易知
即
(k为正整数)
首先我们可以证明一下结论:
结论①:
不能是质数或1。
证明:
b不能是1显然。
假设
是质数,那
的因子只有
,即
只能分别取1和b的倍数,这与
矛盾。故①得证。
结论②:
不能是质数幂(即
)
证明:
假设
,设
,则
,由扩展欧几里得得知
有正整数解的充要条件是
故
。但因为
,故
的质因子里没有
,即
,矛盾。故②得证。
由结论①②可知结论③:
的质因子至少拥有两个。
根据③,我们设
,令
易知
故
必有解,可以用扩展欧几里得求出
。
需要注意的是,如果最后
,其实不需要对扩展欧几里得的解做一些操作,只需要调换
的位置即可。
AC代码(123ms)
#include <bits/stdc++.h>
using namespace std;
const int MAXN=5e6;
int prime[1000];//素数数组
bool is_prime[MAXN+10];//is_pri[i]表示i是否是素数
int sieve()//埃式筛
{
int n=MAXN;
int p=0;
for(int i=0; i<=n; i++)
is_prime[i]=true;
is_prime[0]=is_prime[1]=false;
is_prime[2]=true;
for(int i=2; i<=sqrt(n); i++)
{
if (is_prime[i])
{
prime[++p]=i;
for(int j=2*i; j<=n; j+=i)
is_prime[j]=false;
}
}
return p;
}
long long extended_gcd(long long a, long long b, long long &x, long long &y)
//扩展gcd
{
long long r, t;
if (b==0)
{
x=1;
y=0;
return a;
}
r=extended_gcd(b, a%b, x, y);
t=x;
x=y;
y=t-(a/b)*y;
return r;
}
long long solve_exgcd(long long a, long long b, long long c, long long &x, long long &y)
{
long long p=extended_gcd(a, b, x, y);
if (c%p)
{
x=-1;
y=-1;
return -1;
}
x*=(c/p);
y*=(c/p);
return 0;
}
void solve1()
{
long long pp=sieve();
int t;
scanf("%d", &t);
while(t--)
{
long long a, b;
scanf("%lld%lld", &a, &b);
if (__gcd(a, b)!=1)// ka/kb
{
long long v=__gcd(a, b);
a/=v;
b/=v;
printf("%lld %lld %lld %lld\n", a+1, b, 1, b);
continue;
}
else
{
if (b==1 || is_prime[b])//特判无解情况1
{
printf("-1 -1 -1 -1\n");
continue;
}
long long sum=0;
long long tmp,time=0;
long long bb=b;
for(int i=1;i<=pp && bb!=1;i++)
{
if(bb%prime[i]==0)
{
tmp=prime[i];
while(bb%prime[i]==0)
{
bb/=prime[i];
time++;
}
break;
}
}
if(bb==1)//特判情况2
{
printf("-1 -1 -1 -1\n");
continue;
}
long long d=1;
for(int i=1; i<=time; i++)
{
d*=tmp;
}
// printf("d=%lld\n",d);
long long f=bb;
long long c=0, e=0;
solve_exgcd(f, d, a, c, e);
if (c<0 && e>0)
printf("%lld %lld %lld %lld\n", e, f, -c, d);//两个调过来
else
printf("%lld %lld %lld %lld\n", c, d, -e, f);
}
}
}
int main()
{
// ios_base::sync_with_stdio(false);
// cin.tie(0);
// cout.tie(0);
#ifdef ACM_LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
long long test_index_for_debug=1;
char acm_local_for_debug;
while(cin>>acm_local_for_debug)
{
cin.putback(acm_local_for_debug);
if (test_index_for_debug>100)
{
throw runtime_error("Check the stdin!!!");
}
auto start_clock_for_debug=clock();
solve1();
auto end_clock_for_debug=clock();
cout<<"\nTest "<<test_index_for_debug<<" successful"<<endl;
cerr<<"Test "<<test_index_for_debug++<<" Run Time: "
<<double(end_clock_for_debug-start_clock_for_debug)/CLOCKS_PER_SEC<<"s"<<endl;
cout<<"--------------------------------------------------"<<endl;
}
#else
solve1();
#endif
return 0;
}
后记
赛时差一点就对了…
感谢赛后蔡队的指点 (CSLNB!)
DrGilbert 2020.7.18