bzoj 2393 & bzoj 1853 容斥原理

61 篇文章 0 订阅
3 篇文章 0 订阅

我觉得我写不出更合适的题解了:http://www.2cto.com/kf/201412/359333.html

bzoj 2393

var
        l,r,n,m         :longint;
        ans             :int64;
        a,b             :array[0..1050] of int64;
        flag            :array[0..1050] of boolean;
        i,j             :longint;
function gcd(a,b:int64):int64;
begin
   if b=0 then exit(a) else exit(gcd(b,a mod b));
end;

procedure dfs1(x:int64);
begin
   if x>r then exit;
   inc(n);
   a[n]:=x;
   dfs1(x*10+2);
   dfs1(x*10+9);
end;

procedure dfs2(pos,f:longint;lcm:int64);
var
        tt:int64;
begin
   if b[pos]=0 then
   begin
      if (lcm xor 1<>0) then
        inc(ans,f*(r div lcm-(l-1) div lcm));
      exit;
   end;
   dfs2(pos+1,f,lcm);
   tt:=lcm*b[pos] div gcd(lcm,b[pos]);
   if tt>r then exit;
   dfs2(pos+1,-f,tt);
end;

procedure sort(l,r:longint);
var
        i,j:longint;
        x,y:int64;
begin
   i:=l; j:=r; x:=a[(l+r)>>1];
   while (i<=j) do
   begin
      while (a[i]<x) do inc(i);
      while (a[j]>x) do dec(j);
      if (i<=j) then
      begin
         y:=a[i]; a[i]:=a[j]; a[j]:=y;
         inc(i); dec(j);
      end;
   end;
   if i<r then sort(i,r);
   if j>l then sort(l,j);
end;

begin
   read(l,r);
   dfs1(2); dfs1(9);
   sort(1,n);
   for i:=1 to n do
     for j:=i+1 to n do
       if a[j] mod a[i]=0 then flag[j]:=true;
   for i:=n downto 1 do //这里倒着循环跑着简直飞起
     if not flag[i] then
     begin
        inc(m);
        b[m]:=a[i];
     end;
   dfs2(1,-1,1);
   writeln(ans);
end.


bzoj 1853

遇上题一样,注意数据范围是10^10,所以为了防止爆long long在乘的时候强转成double,确定不超的时候再乘

不知道为什么,bzoj上要开{$Q- I- S-}才能过,不然一直OLE ...

 

{$Q- I- S-} 
var
        l,r,n,m         :int64;
        i,j             :longint;
        flag            :array[0..5010] of boolean;
        a,b             :array[0..5010] of int64;
        ans             :qword;
function gcd(a,b:int64):int64;
begin
   if b=0 then exit(a) else exit(gcd(b,a mod b));
end;

procedure dfs1(x:int64);
begin
   if x>r then exit;
   inc(n);
   a[n]:=x;
   dfs1(x*10+6); dfs1(x*10+8);
end;

procedure dfs2(pos,f:longint;lcm:int64);
var
        tt:int64;
begin
   if b[pos]=0 then
   begin
      if (lcm xor 1 <>0) then
         inc(ans,f*(r div lcm-(l-1) div lcm));
      exit;
   end;
   dfs2(pos+1,f,lcm);
   tt:=lcm div gcd(lcm,b[pos]);
   if double(b[pos])*double(tt)>r then exit;
   tt:=tt*b[pos];
   dfs2(pos+1,-f,tt);
end;

procedure sort(l,r:longint);
var
        i,j:longint;
        x,y:int64;
begin
   i:=l; j:=r; x:=a[(l+r)>>1];
   while (i<=j) do
   begin
      while a[i]<x do inc(i);
      while a[j]>x do dec(j);
      if (i<=j) then
      begin
         y:=a[i]; a[i]:=a[j]; a[j]:=y;
         inc(i); dec(j);
      end;
   end;
   if i<r then sort(i,r);
   if j>l then sort(l,j);
end;

begin
   read(l,r);
   dfs1(6); dfs1(8);
   sort(1,n);
   for i:=1 to n do
     for j:=i+1 to n do
       if (a[j] mod a[i]=0) then flag[j]:=true;
   for i:=n downto 1 do
     if not flag[i] then
     begin
        inc(m);
        b[m]:=a[i];
     end;
   dfs2(1,-1,1);
   writeln(ans);
end.

——by Eirlys



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值