题意:对于一个16进制数x,把x的各个数位拿出来,设其为t1,t2,...,定义s(x)为2^t1|2^t2|...,如x=0x3e53,则s(x)=2^3|2^14|2^5|2^3=16424.给出q组询问l,r(l,r也是16进制数,不超过15位),求[l,r]中有多少个数x满足x^s(x)<x.
这题题解写的是个状压数位dp,但是蒟蒻不会数位dp,自己YY了一个做法.
首先,将[l,r]的询问拆成2个前缀和,考虑到十六进制数减1并不方便,可以转化为solve(r)-solve(l),再特判一下l满不满足要求.
考虑求出[0,upper]间的答案.将二进制位从低位向高位,从0开始编号.观察x和s(x)的二进制表示,可以发现当且仅当s(x)的最高位1所在的数位上x也为1时,x^s(x)<x.考虑从0到15枚举这个数位的位置id,下面只需求出不超过upper的数中有多少个数在id位为1,且所有数位都不超过id,且有至少一个数位等于id.发现最后一个条件不好处理,可以将询问拆成2个:设solve(upper,id,lim)表示不超过upper的数中有多少个数在id位为1,且所有数位都不超过lim.所求答案即为solve(upper,id,id)-solve(upper,id,id-1).这个东西是可以扫几遍upper讨论一通求出来的.实现上细节非常恶心比较多.
1 program cf776G; 2 const number=['a'..'f','0'..'9']; 3 list:array[0..15]of char=('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'); 4 var q,i:longint; 5 l,r:string; 6 num:array[char] of longint; 7 ch:char; 8 procedure getstr(var s:string); 9 var ch:char; 10 begin 11 s:=''; 12 read(ch); 13 while not (ch in number) do read(ch); 14 while ch in number do 15 begin 16 s:=s+ch; 17 read(ch); 18 end; 19 end; 20 function check(const x:string):longint; 21 var i:longint; 22 t,this:int64; 23 begin 24 this:=0; 25 for i:=1 to length(x) do this:=this*16+num[x[i]]; 26 t:=0; 27 for i:=1 to length(x) do t:=t or (1 shl num[x[i]]); 28 exit(ord(this xor t<this)); 29 end; 30 function solve2(const upper:string;id,up:longint):int64; 31 var upp,ans:int64; 32 i,this,t:longint; 33 sw:array[0..30] of longint; 34 pow:array[0..20] of int64; 35 begin 36 upp:=0; 37 for i:=1 to length(upper) do upp:=upp*16+num[upper[i]]; 38 for i:=1 to length(upper) do sw[length(upper)-i]:=num[upper[i]]; 39 if(1 shl (id mod 4)>up)or(1 shl id>upp)or(up<0) then exit(0); 40 t:=0; 41 for this:=0 to up do if this and (1 shl (id mod 4))>0 then inc(t); 42 ans:=0; 43 pow[0]:=1; 44 for i:=1 to length(upper) do pow[i]:=pow[i-1]*(up+1); 45 for i:=length(upper)-1 downto 0 do 46 if i=id div 4 then 47 begin 48 if up<sw[i] then 49 begin 50 ans:=ans+t*pow[i]; 51 exit(ans); 52 end; 53 for this:=0 to sw[i]-1 do if this and (1 shl (id mod 4))>0 then 54 ans:=ans+pow[i]; 55 if sw[i] and (1 shl (id mod 4))=0 then exit(ans); 56 end else 57 begin 58 if up<sw[i] then 59 begin 60 if i>id div 4 then ans:=ans+pow[i]*t else ans:=ans+pow[i+1]; 61 exit(ans); 62 end else 63 begin 64 if i>id div 4 then ans:=ans+pow[i-1]*sw[i]*t 65 else ans:=ans+pow[i]*sw[i]; 66 end; 67 end; 68 inc(ans); 69 exit(ans); 70 end; 71 function solve(const upper:string):int64; 72 var ans:int64; 73 k:longint; 74 begin 75 ans:=0; 76 for k:=0 to 15 do 77 ans:=ans+solve2(upper,k,k)-solve2(upper,k,k-1); 78 exit(ans); 79 end; 80 begin 81 for i:=0 to 15 do num[list[i]]:=i; 82 readln(q); 83 for i:=1 to q do 84 begin 85 getstr(l);getstr(r); 86 writeln(solve(r)-solve(l)+check(l)); 87 end; 88 end.