CF1765M Minimum LCM 題解
阿新 • • 發佈:2022-12-06
原題
給出一個整數 \(n\),找出兩個正整數 \(a,b\),使其滿足 \(a+b=n\) 且 \(\operatorname{lcm}(a,b)\) 要儘可能小。
分析
- 如何求 \(\operatorname{lcm}(a,b)\) ?
—— \(\operatorname{lcm}(a,b)=a\times b \div \gcd(a,b)\)
—— \(\gcd(a,b)=\gcd(b,a\bmod b)\)
-
考慮每個詢問 \(O(n)\) 列舉,總時間複雜度為 \(O(tnlogn)\)
(必定炸裂);因此考慮優化每次詢問的時間複雜度 -
若 \(a,b\) 互質,即 \(\gcd(a,b)=1\)
當 \(a=1,b=n-1\) 時,\(\operatorname{lcm}(a,b)=n-1\);
當 \(a>1,b<n-1\) 時,
\(\operatorname{lcm}(a,b)=ab=a(n-a)\)
要證此時不是最優選擇,只需證:
\(a(n-a)=-a^2+an>n-1\)
只需證:
\(a^2-an+n-1<0\)
整理得:
\((a-1)(a-n+1)=(a-1)(1-b)<0\)
因此,只需列舉 \(n\)
p.s 記得開longlong,不然會炸~
AC Code
#include<stdio.h> using namespace std; typedef long long ll; int t; ll gcd(ll x,ll y){return y==0?x:gcd(y,x%y);} ll min(ll x,ll y){return x<y?x:y;} int main(){ // freopen("CF1765M.in","r",stdin); // freopen("CF1765M1.out","w",stdout); scanf("%d",&t); while(t--){ ll n,ans=1145141919810,ansi; scanf("%lld",&n); if(n%2==0){//可考慮特判,這個簡單想想就好了 printf("%lld %lld\n",n/2,n/2); continue; } else if(n%3==0){//這個也可以特判,也很簡單(懶得證了) printf("%lld %lld\n",n/3,n/3*2); continue; } for(ll i=1;i*i<=n;i++){//列舉因數 ll j=n-i; if(ans>i*j/gcd(i,j)) ans=1ll*i*j/gcd(i,j),ansi=i; if(n%i==0){//如果是因數,考慮更新答案 ll p=n/i,q=n-p; if(q==0) continue; if(ans>p*q/gcd(p,q)) ans=1ll*p*q/gcd(p,q),ansi=p; } } printf("%lld %lld\n",ansi,n-ansi); } }