zoukankan      html  css  js  c++  java
  • poj3252

    好了,我的数论渣爆了…………

    首先[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.
    View Code
  • 相关阅读:
    转《编程之美——微软技术面试心得》勘误表
    第一次 学习使用 智能指针
    test _todel
    (转 todo阅读)Android 官方博客 Android应用程序的内存分析(翻译)
    msdn snmp trap 研究可否 重入 转《Multiple Trap Registrations》
    wpbars在博客园开博客了
    创业失败的10个教训总结
    winform 的一种登录方法。
    快速建立Subversion
    (转)SQL Server 按某一字段分组取最大(小)值所在行的数据
  • 原文地址:https://www.cnblogs.com/phile/p/4473295.html
Copyright © 2011-2022 走看看