[jzoj]2538.【NOIP2009TG】Hankson 的趣味题

Link

  https://jzoj.net/senior/#main/show/2538

Description

  Hanks 博士是BT (Bio-Tech,生物技术) 领域的知名专家,他的儿子名叫Hankson。现在,刚刚放学回家的Hankson 正在思考一个有趣的问题。今天在课堂上,老师讲解了如何求两个正整数c1 和c2 的最大公约数和最小公倍数。现在Hankson 认为自己已经熟练地掌握了这些知识,他开始思考一个“求公约数”和“求公倍数”之类问题的“逆问题”,这个问题是这样的:已知正整数a0,a1,b0,b1,设某未知正整数x 满足

  1、x 和a0 的最大公约数是a1;  

  2、x 和b0 的最小公倍数是b1。

  Hankson 的“逆问题”就是求出满足条件的正整数x。但稍加思索之后,他发现这样的x 并不唯一,甚至可能不存在。因此他转而开始考虑如何求解满足条件的x 的个数。请你帮助他编程求解这个问题。

Solution

50分

  显然,答案肯定是最大公约数的倍数,枚举那个数即可。

100分

  如果存在两个数,a,b,分解质因数得

  a=p1q1*p2q2*p3q3......

  b=pp1qq1*pp2qq2*pp3qq3......

  那么,最大公约数和最小公倍数分别如下。

  gcd(a,b)=p1min(q1,qq1)p2min(q2,qq2)p3min(q3,qq3)......

  lcm(a,b)=p1max(q1,qq1)p2max(q2,qq2)p3max(q3,qq3)......

  我们根据这个关系,将题目所给的lcm,也就是b1分解质因数,根据第二条,我们枚举他每个质因数的指数,判断答案即可。

  注意卡常。

Code

{$inline on}
var
        n,x,i,j,g,a0,a1,b0,b1,now,ans:longint;
        sm:array[1..10,1..2] of longint;
function gcd(x,y:longint):longint; inline;
begin
        if x mod y=0 then exit(y);
        exit(gcd(y,x mod y));
end;

procedure dg(k:longint;ka:int64);
var
        i:longint;
begin
        if k>g then
        begin
                if (gcd(ka,a0)=a1) and (ka div gcd(ka,b0)*b0=b1) then
                        inc(ans);
                exit;
        end;

        for i:=0 to sm[k,2] do
        begin
                dg(k+1,ka);
                ka:=ka*sm[k,1];
        end;
end;
begin
        readln(n);
        for i:=1 to n do
        begin
                readln(a0,a1,b0,b1);
                x:=b1;
                g:=0;
                fillchar(sm,sizeof(sm),0);

                for j:=2 to trunc(sqrt(b1)) do
                begin
                        if x mod j=0 then
                        begin
                                inc(g);
                                sm[g,1]:=j;
                                while x mod j=0 do
                                begin
                                        x:=x div j;
                                        inc(sm[g,2]);
                                end;
                                if x=1 then break;
                        end;
                end;

                if x>1 then
                begin
                        inc(g);
                        sm[g,1]:=x;
                        sm[g,2]:=1;
                end;
                ans:=0;

                dg(1,1);

                writeln(ans);
        end;
end.
原文地址:https://www.cnblogs.com/philchieh/p/7476995.html