cf776G.Sherlock and the Encrypted Data

题意:对于一个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.
View Code

 

转载于:https://www.cnblogs.com/lkmcfj/p/6473927.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值