题意:已知gcd(a,b)和lcm(a,b),求a,b使得a+b最小。
令p=lca(a,b)/gcd(a,b),那么显然a=pu,b=pv且gcd(u,v)=1。那么只需要将p分解质因数,然后把相同的质因数并起来,一遍dfs即可。
质因数分解的pollard_pho启发式算法,可以在期望n^(1/4)的时间内找到n的一个因数,然后递归分解即可。显然分解的次数不会太多,因此时间上可以接受。
AC代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cstdlib> #include<algorithm> #define ll long long #define N 205 using namespace std; ll n,m,c[N],a[N],ansx,ansy; int cnt; ll ksc(ll x,ll y,ll p){ ll t=0; for (; y; y>>=1,x=(x<<1)%p) if (y&1) t=(t+x)%p; return t; } ll ksm(ll x,ll y,ll p){ ll t=1; for (; y; y>>=1,x=ksc(x,x,p)) if (y&1) t=ksc(t,x,p); return t; } bool isprm(ll x){ if (x==2) return 1; if (x==1 || !(x&1)) return 0; ll t=x-1; int len=0,i,j; for (; !(t&1); t>>=1) len++; for (i=1; i<=10; i++){ ll k=ksm(rand()%(x-1)+1,t,x); for (j=1; j<=len; j++,k=ksc(k,k,x)) if (j<len-1 && ksc(k,k,x)==1 && k!=1 && k!=x-1) return 0; if (k!=1) return 0; } return 1; } ll gcd(ll x,ll y){ return (y)?gcd(y,x%y):x; } ll pho(ll x){ ll u=rand()%(x-1)+1,v=u,w,t=1; int i=2,k=2; while (!w || w==2) w=rand()%(x-1)+1; for (; t==1; i++){ if (i==k){ v=u; k<<=1; } u=(ksc(u,u,x)+x-w)%x; t=gcd(v-u+x,x); } return t; } void divide(ll x){ if (x==1) return; else if (isprm(x)) c[++c[0]]=x; else if (!(x&1)){ c[++c[0]]=2; divide(x/2); } else{ ll t=pho(x); divide(t); divide(x/t); } } void dfs(int k,ll x,ll y){ if (x+y>=ansx+ansy) return; if (k>cnt){ ansx=x; ansy=y; return; } dfs(k+1,x*a[k],y); dfs(k+1,x,y*a[k]); } int main(){ srand(20160304); while (~scanf("%lld%lld",&m,&n)){ c[0]=0; divide(n/m); sort(c+1,c+c[0]+1); int i; cnt=0; for (i=1; i<=c[0]; i++) if (i==1 || c[i]!=c[i-1]) a[++cnt]=c[i]; else a[cnt]*=c[i]; ansx=1; ansy=n/m; dfs(1,1,1); if (ansx>ansy) swap(ansx,ansy); printf("%lld %lld\n",ansx*m,ansy*m); } return 0; }
2016.3.4