zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    Codeforces 每日一练 1213G+961E+1282B2
    AtCoder Beginner Contest 161题解
    Codeforces每日一练 495B+55C+1280C
    CF1062E 线段树/LCA
    Codeforces Round #697 (Div. 3) 题解
    Codeforces Round #511 (Div. 2) A~D题解
    Atcoder ABC 189 题解
    CF1093G 高维曼哈顿距离/线段树
    CF1117D Magic Gems 矩阵快速幂 DP
    CF1106E Lunar New Year and Red Envelopes DP
  • 原文地址:https://www.cnblogs.com/2018zxy/p/10328338.html
Copyright © 2011-2022 走看看