好了,我的数论渣爆了…………
首先[n,m]内的round number显然就是f[m]-f[n-1]
即问0~x内有多少round number;
设x的二进制位数为t;
首先很好分析出在这个范围
若某数的二进制位数<t,则首位1不动,后面组合即可;
然后被卡在当二进制位数为t的round number有多少这招情况;
后来看了别人的解题报告才恍然大悟;
对于x,不算首位的1,只要把当前某一个1改成0,并对后面位数重新01组合就一定小于x,
于是
对于x的每一位1,对后面重新组合即可
显然最终答案不会爆maxlongint
现在想想,其实就是数位dp的思想
1 var c:array[0..40,0..40] of longint; 2 a:array[0..40] of longint; 3 n,m:longint; 4 procedure prepare; //预处理组合数 5 var i,j:longint; 6 begin 7 c[0,0]:=1; 8 for i:=1 to 31 do 9 begin 10 c[i,0]:=1; 11 c[i,i]:=1; 12 for j:=1 to i-1 do 13 c[i,j]:=c[i-1,j]+c[i-1,j-1]; 14 end; 15 end; 16 17 function count(x:longint):longint; 18 var p,t,i,j,q,s1,s0:longint; 19 begin 20 fillchar(a,sizeof(a),0); 21 if x=0 then exit(1); 22 p:=x; 23 t:=0; 24 while p<>0 do //十转二 25 begin 26 t:=t+1; 27 a[t]:=p mod 2; 28 p:=p shr 1; 29 end; 30 count:=1; //考虑0 31 for i:=2 to t-1 do //当二进制位数小于t 32 begin 33 if i mod 2=1 then q:=(i-1) div 2+1 //保证0比1多 34 else q:=i div 2; 35 for j:=q to i-1 do 36 count:=count+c[i-1,j]; 37 end; 38 s0:=0; 39 s1:=0; 40 for i:=1 to t do //先特判x是否是round number 41 if a[i]=1 then inc(s1) else inc(s0); 42 if s0>=s1 then count:=count+1; 43 s0:=0; 44 s1:=1; 45 for i:=t-1 downto 1 do 46 if a[i]=1 then 47 begin 48 for j:=i-1 downto 0 do //j表示后面可能出现0的个数 49 if j+s0+1>=i-1-j+s1 then //保证0比1多,i-1表示当前位1后面的,+1表示将这位1变成0后后面重新组合 50 count:=count+c[i-1,j] 51 else break; 52 inc(s1); //别忘统计前面的0,1个数,后面的排列情况是由起决定的 53 end 54 else inc(s0); 55 end; 56 begin 57 readln(n,m); 58 prepare; 59 writeln(count(m)-count(n-1)); //经常用到的转化思想 60 end.