zoukankan      html  css  js  c++  java
  • URAL 1057 Amount of Degrees (数位dp)

    Create a code to determine the amount of integers, lying in the set [X;Y] and being a sum of exactly K different integer degrees of B.
    Example. Let X=15, Y=20, K=2, B=2. By this example 3 numbers are the sum of exactly two integer degrees of number 2:
    17 = 24+20,
    18 = 24+21,
    20 = 24+22.

    Input

    The first line of input contains integers X and Y, separated with a space (1 ≤ X ≤ Y ≤ 231−1). The next two lines contain integers K and B (1 ≤ K ≤ 20; 2 ≤ B ≤ 10).

    Output

    Output should contain a single integer — the amount of integers, lying between X and Y, being a sum of exactly K different integer degrees of B.

    Sample

    Input

    15 20

    2 2

    Output

    3

    所求的数为互不相等的幂之和,亦即其B 进制表示的各位数字都只能是0和1。因此,我们只需讨论二进制的情况,其他进制都可以转化为二进制求解。

    很显然,数据范围较大,不可能采用枚举法,算法复杂度必须是log(n)级别,因此我们要从数位上下手。

    本题区间满足区间减法,因此可以进一步简化问题:令count[i..j]表示[i..j]区间内合法数的个数,则count[i..j]=count[0..j]-count[0..i-1]。换句话说,给定n,我们只需求出从0 到n有多少个符合条件的数。
    假设n=13,其二进制表示为1101,K=3。我们的目标是求出0 到13中二进制表示含3个1 的数的个数。为了方便思考,让我们画出一棵高度为4 的完全二叉树:

    为了方便起见,树的根用0 表示。这样,这棵高度为4 的完全二叉树就可以表示所有4位二进制数(0..24-1),每一个叶子节点代表一个数。其中,红色路径表示n。所有小于n的
    数组成了三棵子树,分别用蓝色、绿色、紫色表示。因此,统计小于13 的数,就只需统计这三棵完整的完全二叉树:统计蓝子树内含3 个1的数的个数、统计绿子树内含2 个1 的数的个数(因为从根到此处的路径上已经有1 个1),

    以及统计紫子树内含1个1 的数的个数。
    注意到,只要是高度相同的子树统计结果一定相同。而需要统计的子树都是“右转”时遇到的。当然,我们不能忘记统计n 本身。实际上,在算法最初时将n 自加1,可以避免讨论n
    本身,但是需要注意防止上溢。剩下的问题就是,如何统计一棵高度为i的完全二叉树内二进制表示中恰好含有j个1的数的个数。这很容易用递推求出:设f[i,j]表示所求,则分别统计左右子树内符合条件数的个数

    ,有f[i,j]=f[i-1,j]+f[i-1,j-1]。
    这样,我们就得出了询问的算法:首先预处理f,然后对于输入n,我们在假想的完全二叉树中,从根走到n所在的叶子,每次向右转时统计左子树内数的个数。

    最后的问题就是如何处理非二进制。对于询问n,我们需要求出不超过n的最大B进制表示只含0、1的数:找到n 的左起第一位非0、1 的数位,将它变为1,并将右面所有数位设为1。将得到的B进制表示视为二进制进行询问即可。

    代码如下:

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 int f[35][35],d[35];
     5 void init ()//其实这就是个杨辉三角形
     6 {
     7     memset(f,0,sizeof f);
     8     f[0][0]=1;
     9     for (int i=1;i<=31;++i)
    10     {
    11         f[i][0]=1;
    12         for (int j=1;j<=i;++j)
    13         f[i][j]=f[i-1][j-1]+f[i-1][j];
    14     }
    15 }
    16 int calc (int x,int k)
    17 {
    18     int tot=0,ans=0;
    19     for (int i=31;i>0;--i)
    20 {
    21     if (x&(1<<i))//x的第i+1位是不是1
    22         {
    23             tot++;
    24             //printf("i=%d tot=%d
    ",i,tot);
    25             if (tot>k)
    26             break;
    27             x^=(1<<i);//把这位削成0
    28         }
    29         if (1<<(i-1)&x)//能否右转,能则统计左子树,即i-1位选0
    30         {
    31             //printf("i-1=%d tot=%d f=%d
    ",i-1,tot,f[i-1][k-tot]);
    32             ans+=f[i-1][k-tot];
    33         }
    34 
    35     }
    36     if (tot+x==k)//如果全都是1,则没有统计,++ans补上
    37     ans++;
    38     //printf("ans=%d
    ",ans);
    39     return ans;
    40 }
    41 int transfer (int b,int x)//将x,y转换成等价的二进制数
    42 {
    43     int m=0,ans=0;
    44     while (x)
    45     {
    46         d[m++]=x%b;
    47         x/=b;
    48     }
    49     for (int i=m-1;i>=0;--i)
    50     {
    51         if (d[i]>1)
    52         {
    53             for (int j=i;j>=0;j--)
    54             ans|=(1<<j);
    55         }
    56         else
    57         ans|=d[i]<<i;
    58     }
    59     return ans;
    60 }
    61 int main()
    62 {
    63     //freopen("de,txt","r",stdin);
    64     long long int x,y;
    65     int k,b;
    66     init();
    67     while (~scanf("%lld%lld",&x,&y))
    68     {
    69         scanf("%d %d",&k,&b);
    70         x=transfer(b,x-1);
    71         y=transfer(b,y);
    72         printf("%d
    ",calc(y,k)-calc(x,k));
    73     }
    74     return 0;
    75 }

    论文参照《浅谈数位类统计问题》 作者:山东省青岛第二中学 刘聪

  • 相关阅读:
    《Java编程思想》阅读笔记二
    《Java编程思想》阅读笔记一
    【Android开发日记】之入门篇(十五)——ViewPager+自定义无限ViewPager
    将你的代码上传 Bintray 仓库
    Volley框架的流程图分析
    Volley框架的使用
    【Android开发日记】之基础篇(二)——Android的动画效果
    maven项目的多级目录
    【Android开发日记】之基础篇(一)——TextView+SpannableStringBuilder
    Android APP安装后不在桌面显示图标的应用场景举例和实现方法
  • 原文地址:https://www.cnblogs.com/agenthtb/p/5897784.html
Copyright © 2011-2022 走看看