一,题目
![](https://i-blog.csdnimg.cn/blog_migrate/891862b046e6e411a79624102de95059.png)
二,思路
1,当n为质数的时候。设a+b=n,g为gcd(a,b),此时,a可以表示为x*g,b可表示为y*g,(x和y是未知的普通的数,设此数是为了方便表示,无他目的),那么(x+y)*g=n,如果n是质数,那么g只能等于1或n,因为x和y是正整数,所以x+y>1,所以x+y=n,g=1,所以gcd(a,b)=1,所以a和b必然互质,而lcm(a,b)=a*b/gcd(a,b)。这时我们发现,求lcm(a,b)的问题转化为a+b为定值,求a*b最小值的问题。根据基本不等式,a+b为定值时,a和b的差越大,a*b越小,所以a和b其中一个为1,另一个为n-1。
2,(1)当n为合数的时候,设a+b=n,g为gcd(a,b),此时,a可以表示为x*g,b可表示为y*g,因为(x+y)*g=n,所以n可表示为z*g(所以说gcd(a,b)是n的一个因数)。所以a+b=n<=>x*g+y*g=z*g。忽略g,这时我们发现,求lcm(a,b)的问题转化为x+y为定值z,求x*y的最小值,依旧根据基本不等式,x+y为定值时,x和y差越大,x*y越小。所以x和y其中一个为1,另一个为z-1;把g拿过来讨论,我们只要枚举每个满足条件的g(或者说n的因数),把这时的x*y最小值找出来就行。
(2)但此时有个问题,n可以是1e9。所以不能暴力枚举。但我们发现,当x和y其中一个是1,另一个是z-1时,a+b=n<=>g+(z-1)*g=z*g,令x=1,y=z-1,,则a=g,b=y*g所以此时(y+1)*g=z*g,
g+y*g=z*g,我们发现,枚举g的同时,z也被枚举,比如6这个数,枚举1的同时6被枚举,枚举2
的同时,3也被枚举。所以我们只要枚举差不多一半的因数g得到的结果,因为枚举另一半的与之对应的数z枚举得到的结果是一样的。这时的时间复杂度为O();
举个例子:n=100
当g=2时,z=50,y*g=98,a(即g)和b(即y*g)最小公倍数为98.
当g=4时,z=25,y*g=96,a(即g)和b(即y*g)最小公倍数为96.
当g=5时,z=20,y*g=95,a(即g)和b(即y*g)最小公倍数为95.
当g=10时,z=10,y*g=10,a(即g)和b(即y*g)最小公倍数为10.
当g=20时,z=5,y*g=95,a(即g)和b(即y*g)最小公倍数为95.
当g=25时,z=4,y*g=96,a(即g)和b(即y*g)最小公倍数为96.
当g=50时,z=2,y*g=98,a(即g)和b(即y*g)最小公倍数为98.
我们可以看到上下是对称的,所以我们只要枚举差不多一半的因数g得到的结果,因为枚举另一半的与之对应的因数z枚举得到的结果是一样的。
(3)总结,现在我们要做的是根据g+y*g=z*g<=>a+b=n这个式子,先枚举n的每一个因数g,用MIN对比每一个g和y*g最大公因数,如果MIN大于这个最大公因数,拿ans储存这个g,枚举到即可。
三,代码
(由于本人太蒟蒻,枚举g+y*g=z*g中g的每一个数的时候,总是出现问题,这里就不枚举g了,枚举z算了)
#include<iostream>
#define int long long
#define uep(z,a,b) for(int z=a;z<=b;++z)
#define rep(z,a,b) for(int z=a;z>=b;--z)
#define pb push_back
#define pf pudh_front
using namespace std;
int gcd(int a, int b)
{
while (a ^= b ^= a ^= b %= a);
return b;
}
int f(int n)
{
int ans = 1, MIN = 1000000001;
for (int z = 2; z * z <= n; ++z)
{
if (n % z == 0)
{
int a = n / z, b = n - a;
int lcm = a * b / gcd(a, b);
if (lcm < MIN) ans = z, MIN = lcm;
}
}
return ans;
}
signed main()
{
int t, n;
cin >> t;
while (t--)
{
cin >> n;
int ans = f(n), tmp = n / ans;
if (ans != 1) cout << tmp << " " << n - tmp << endl;
//如果ans进入f函数for循环出来后仍然为1,那么说明n是质数,这时要输出1和n-1而不是上面的代码。
else cout << 1 << " " << n - 1 << endl;
}
return 0;
}
(不会有人真从头到尾全看完了吧,这题很简单,我只是用另一种办法来水贴)