jzoj P2151【2017.7.7普及】分数

83 篇文章 0 订阅
20 篇文章 0 订阅

题目大意:
求n1个a[i]的乘积跟n2个b[i]乘积的既约分数,(既约分数就是分子分母最大公约数为1的分数)。

对于20%的数据,n1,n2<=10,Ai,Bi<=10
对于60%的数据,n1,n2<=1000,Ai,Bi<=1000
对于100%的数据,n1,n2<=100000,Ai,Bi<=10000
数据保证不会出现分数的值为0的情况

题解:
20分的就是直接得到乘积后直接用辗转相除法约去最大公因数即可
时间复杂度:O(n)
60分就使用高精度,把两个序列两两去除公因数
AC的话:
因为Ai,Bi<=10000,所以可以先塞素数,然后对其分解质因数,把合数化成质数(质数则不变),然后2个序列a,b都这样做,最后用两个序列的分解出来的数相互抵消,类似于去重。
然后将2个序列剩下的数分别用高精度算出乘积,然后直接输出
PS:抵消完后的序列乘积满足既约分数。
不过我们在高精度的时候要用到压位,不然容易超时,即改变进制,因为Ai,Bi<=10000,所以长整型最大压位到200000左右…
时间复杂度O(n*m)
M为常数,不会超过100,因为10000以内我们只需分解到100即可,分解完后如果还大于1,则可证这一定是个质数

var
    a,b,ansa,rp:array [0..100001] of longint;
    p:array [0..10001] of boolean;
    kp:array [0..10001] of longint;
    x,i,j,k,l,n,m,la:longint;

procedure gjd(k:longint);
var
    j,x:longint;
begin
    x:=0;
    for j:=1 to la do
    begin
         ansa[j]:=k*ansa[j]+x;
         x:=ansa[j] div 100000;
         ansa[j]:=ansa[j] mod 100000;
    end;
    ansa[la+1]:=x;
    la:=la+1;
    if ansa[la]=0 then dec(la);
end;

function check(p:longint):string;
begin
    check:='';
    if p<=9999 then check:=check+'0';
    if p<=999 then check:=check+'0';
    if p<=99 then check:=check+'0';
    if p<=9 then check:=check+'0';
    exit(check);
end;

procedure ag(k:longint);
begin
     inc(a[kp[k]]);
     if k=kp[k] then exit;
     ag(k div kp[k]);
end;
procedure bg(k:longint);
begin
     inc(b[kp[k]]);
     if k=kp[k] then exit;
     bg(k div kp[k]);
end;

begin
   assign(input,'count.in'); reset(input);
    assign(output,'count.out'); rewrite(output);
    read(n);
    for i:=1 to n do
    begin
         read(x);
         inc(a[x]);
    end;
    readln;
    read(m);
    for i:=1 to m do
    begin
         read(x);
         inc(b[x]);
    end;
    readln;

    p[1]:=true;
    kp[1]:=1;
    for i:=2 to 10000 do
    if not(p[i]) then
    begin
          j:=1;
          while i*j<=10000 do
          begin
               p[i*j]:=true;
               if kp[i*j]=0
                  then kp[i*j]:=i;
               inc(j);
          end;
    end;

    for i:=2 to 10000 do
    begin
         k:=a[i]; a[i]:=0;
         for j:=1 to k do ag(i);
         k:=b[i]; b[i]:=0;
         for j:=1 to k do bg(i);
    end;
    for i:=2 to 10000 do
    begin
         if a[i]>=b[i]
            then begin
                     a[i]:=a[i]-b[i];
                     b[i]:=0;
                 end
            else begin
                     b[i]:=b[i]-a[i];
                     a[i]:=0;
                 end;
    end;

    ansa[1]:=1;
    la:=1;
    for i:=2 to 10000 do
      for j:=1 to a[i] do gjd(i);
    write(ansa[la]);
    ansa[la]:=0;
    for i:=la-1 downto 1 do
    begin
          write(check(ansa[i]));
          write(ansa[i]);
          ansa[i]:=0;
    end;

    la:=1;
    ansa[1]:=1;
    for i:=2 to 10000 do
      for j:=1 to b[i] do gjd(i);
    write(' ');
    if (ansa[1]=1) and (la=1)
       then begin end
       else begin
                 write(ansa[la]);
                 for i:=la-1 downto 1 do
                 begin
                       write(check(ansa[i]));
                       write(ansa[i]);
                 end;
            end;
    close(input); close(output);
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值