Amount of Degrees(数位dp)

Posted 2018zxy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Amount of Degrees(数位dp)相关的知识,希望对你有一定的参考价值。

题目链接:传送门

思路:考虑二进制数字的情况,可以写成一个二叉树的形式,然后考虑区间[i……j]中满足的个数=[0……j]-[0……i-1]。

所以统计树高为i,中有j个1的数的个数。

对于一个二进制数字,求出每次向右转时的左子树内的个数。

对于非二进制数字,就转换为二进制数字后再求解。

技术分享图片
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 120;
int dp[maxn][maxn];
typedef long long LL;
void Init() //初始化,dp[i][j]代表高度为i的二进制树中恰好有j个1的数的个数 
{
    dp[0][0]=1;
    for(int i=1;i<=31;i++){
        dp[i][0]=dp[i-1][0];
        for(int j=1;j<=i;j++)
        dp[i][j]=dp[i-1][j]+dp[i-1][j-1];
    }
}
int change(int x,int b) //b进制转换为2进制 
{
    int tot=0,ans=0;LL tmp=1;
    while(tmp*b<=x){
        tmp*=b;tot++;
    }
    while(tmp){
        if(x>=tmp){
            ans+=(1<<tot);
            x-=tmp;
        }
        tmp/=b;tot--;
    }
    return ans;
}
int cal(int x,int k) //求二进制中k个数组成x的组合的个数 
{
    int tot=0,ans=0;
    for(int i=31;i>0;i--){
        if(x&(1<<i)){ //统计当前位是否为1 
            tot++;
            if(tot>k) break;
            x=x^(1<<i);
        }
        if((1<<(i-1))<=x) ans+=dp[i-1][k-tot];  //统计左子树中的个数 
    }
    if(tot+x==k) ans++; //判断端点是否由k个数组成 
    return ans;
}
int main(void)
{
    int x,y,k,b;
    Init();
    while(~scanf("%d%d%d%d",&x,&y,&k,&b)){
        printf("%d
",cal(change(y,b),k)-cal(change(x-1,b),k));
    }
    return 0;
}
View Code

 

以上是关于Amount of Degrees(数位dp)的主要内容,如果未能解决你的问题,请参考以下文章

Timus Online Judge 1057. Amount of Degrees(数位dp)

Amount of Degrees(数位dp)

Amount of Degrees 数位DP

ural 1057 Amount of degrees 数位dp

URAL 1057 Amount of Degrees

Amount of Degrees