两题是类似的,这里说一下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.