两题是类似的,这里说一下bzoj1853

首先我们求出所有的幸运号码,注意如果存在x是y的倍数则x不算在内,避免之后重复计算

下面我们就要统计幸运号码的倍数了,这显然是要用到容斥原理的

但是幸运号码很多,如果直接暴力找几个幸运号码的公倍数做容斥原理弄会TLE的;

因此我们想到在搜索中剪枝,如果几个幸运号码的公倍数已经大于r,

那么我们一定不会再用这几个幸运号码和别的幸运号码求公倍数了

为了体现这个剪枝的威力,我们穷举幸运号码的时候应该从大往小搜索;

 1 var b:array[0..10010] of int64;
 2     a:array[0..20] of longint;
 3     m,t,k,i:longint;
 4     s,x,l,r,ans:int64;
 5     f:boolean;
 6 
 7 function gcd(a,b:int64):int64;
 8   begin
 9     if b=0 then exit(a)
10     else exit(gcd(b,a mod b));
11   end;
12 
13 procedure dfs(j,t:longint;x:int64);
14   var y:int64;
15   begin
16     if j=0 then
17     begin
18       if t mod 2=1 then ans:=ans+r div x-(l-1) div x  //容斥原理
19       else if t>0 then ans:=ans-r div x+(l-1) div x
20     end
21     else begin
22       dfs(j-1,t,x);
23       y:=x div gcd(b[j],x);
24       if double(b[j])*double(y)<=r then  //double是防止爆int64
25         dfs(j-1,t+1,b[j]*y);
26     end;
27   end;
28 
29 begin
30   readln(l,r);
31   t:=0;
32   x:=r;
33   while x<>0 do
34   begin
35     inc(t);
36     x:=x div 10;
37   end;
38   fillchar(a,sizeof(a),255);
39   m:=0;
40   while a[0]=-1 do
41   begin
42     s:=0;
43     for i:=1 to t do
44       if a[i]=0 then s:=s*10+6
45       else if a[i]=1 then s:=s*10+8;
46     if s>r then break
47     else if s<>0 then
48     begin
49       f:=true;
50       for i:=1 to m do
51         if s mod b[i]=0 then
52         begin
53           f:=false;
54           break;
55         end;
56       if f then
57       begin
58         inc(m);
59         b[m]:=s;
60       end;
61     end;
62     k:=t;
63     while a[k]=1 do
64     begin
65       a[k]:=0;
66       dec(k);
67     end;
68     inc(a[k]);
69   end;
70   dfs(m,0,1);
71   writeln(ans);
72 end.
View Code

 

posted on 2014-10-07 21:34  acphile  阅读(1049)  评论(0编辑  收藏  举报