CF 613 Div.2-C Fadi and LCM

题目链接

http://codeforces.com/contest/1285/problem/C

题目大意

给一个数,作为两个正整数的lcm,让你最小化这两个数中最大的数,并输出。

解题思路

一开始想到的是二分,二分b枚举a,交上果断wa,好像不满足二分性质,改变思路:
对于两个数的lcm,设这两个数分别为a、b,对a,b进行质因子分解:
a = p 1 s 1 ∗ p 2 s 2 ∗ . . . ∗ p n s n a=p_1^{s_1}*p_2^{s_2}*...*p_n^{s_n} a=p1s1p2s2...pnsn
b = p 1 t 1 ∗ p 2 t 2 ∗ . . . ∗ p n t n b=p_1^{t_1}*p_2^{t_2}*...*p_n^{t_n} b=p1t1p2t2...pntn
则: l c m ( a , b ) = p 1 m a x ( s 1 , t 1 ) ∗ p 2 m a x ( s 2 , t 2 ) ∗ . . . ∗ p n m a x ( s n , t n ) lcm(a,b)=p_1^{max(s_1,t_1)}*p_2^{max(s_2,t_2)}*...*p_n^{max(s_n,t_n)} lcm(a,b)=p1max(s1,t1)p2max(s2,t2)...pnmax(sn,tn)
现在咱已经知道了lcm(a,b),所以可以先对其进行质因子分解,然后就知道了 p 1 , . . . p n p_1,...p_n p1,...pn以及对应的幂指数,我们要得到a和b,其实是逆过程找最小值,由于n不会太大,所以可以二进制枚举,将各项质因子的幂重新分配到a,b,取枚举中的max(a,b)最小的那组。
举个例子:
假设lcm(a,b)=24.
24 = 2 3 ∗ 3 1 24=2^3*3^1 24=2331
二进制枚举到(1<<2)-1,也就是1-3
1: 01 则 a = 2 0 ∗ 3 1 , b = 2 3 ∗ 3 0 a=2^0*3^1,b=2^3*3^0 a=2031,b=2330 所以: a = 3 , b = 4 a=3,b=4 a=3,b=4
2: 10 则 a = 2 3 ∗ 3 0 , b = 2 0 ∗ 3 1 a=2^3*3^0,b=2^0*3^1 a=2330,b=2031 所以: a = 4 , b = 3 a=4,b=3 a=4,b=3
3: 11 则 a = 2 3 ∗ 3 1 , b = 2 0 ∗ 3 0 a=2^3*3^1,b=2^0*3^0 a=2331,b=2030 所以: a = 24 , b = 1 a=24,b=1 a=24,b=1
显然前两种max(a,b)最小,所以答案为(3,4).

参考代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair<ll,int> P;
const ll inf=1e12+7;
const int maxn=1e5+7;
#define ft first
#define sd second
#define pb push_back
int t;
ll x;
int len=0;
vector<P> v;
vector<int> s;
void getp(ll xx){//质因子分解
    for(ll i=2;i*i<=xx;i++){//昨晚这里忘记开long long,一直TLE,快哭了 
        v.pb(P(i,0));
        while(xx%i==0)xx/=i,++v.back().sd;
        if(!v.back().sd)v.pop_back();
    }
    if(xx>1)v.pb(P(xx,1));
}
ll qpow(ll a,ll n){
    ll ret=1;
    while(n){
        if(n&1)ret*=a;
        a*=a;
        n>>=1;
    }
    return ret;
}
void solve(int xx,ll &l,ll &r){//二进制枚举
    s.clear();
    ll a=1,b=1;
    while(xx){
        s.pb(xx%2);
        xx/=2;
    }
    int lwl=s.size();
    for(int i=lwl+1;i<=len;i++)s.pb(0);
    for(int i=0;i<len;i++){
        if(a>=r||b>=r)return;
        if(s[i]==1){
            if(v[i].sd==1)a*=v[i].ft;
            else a*=qpow(v[i].ft,v[i].sd);
        }
        else {
            if(v[i].sd==1)b*=v[i].ft;
            else b*=qpow(v[i].ft,v[i].sd);
        }
    }
    if(a>b)swap(a,b);
    if(b<r){
        r=b,l=a;
    }
}
int main()
{
    cin>>x;
    v.clear();
    ll no=x;
    getp(no);
    len=(int)v.size();
    if(len==1||len==0){
        printf("1 %lld\n",x);return 0;
    }
    ll l=1,r=x;
    ll n=1<<len;
    for(int i=1;i<n;i++){
        solve(i,l,r);
    }
    if(l>r)swap(l,r);
    cout<<l<<' '<<r<<'\n';
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值