• URAL 1057 Amount of Degrees


    数位DP,题意转换一下就是说,其B进制表示的各位数字都只能是0和1。

    求区间L....R之间的符合要求数字有几个,可以使用容斥原理。

    计算小于X的符合要求的数有几个的时候,我们需要先找到比X小的最大的符合要求的数字,然后以这个数字往下推导,和之前做的数位DP方法一样了。

    dp[i][j][k]表示的是i位,首位数字为j,有k个1的数的个数是多少。

    递推式很容易写出来:

    dp[i][0][k] += dp[i - 1][0][k];
    dp[i][0][k] += dp[i - 1][1][k];

    dp[i][1][k] += dp[i - 1][0][k - 1];
    dp[i][1][k] += dp[i - 1][1][k - 1];

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    
    int dp[35][5][30];
    int B,K;
    int L,R;
    int p[35];
    int tot;
    
    void init()
    {
        memset(dp,0,sizeof dp);
    
        dp[1][0][0]=1;
        dp[1][1][1]=1;
    
        for(int i=2; i<=32; i++)
        {
            for(int j=0; j<=1; j++)
            {
                for(int k=0; k<=20; k++)
                {
                    if(j==0)
                    {
                        dp[i][0][k]+=dp[i-1][0][k];
                        dp[i][0][k]+=dp[i-1][1][k];
                    }
                    else if(j==1)
                    {
                        if(k-1>=0)
                        {
                            dp[i][1][k]+=dp[i-1][0][k-1];
                            dp[i][1][k]+=dp[i-1][1][k-1];
                        }
                    }
                }
            }
        }
    }
    
    int f(int x)
    {
        tot=1;
        while(x)
        {
            p[tot++]=x%B;
            x=x/B;
        }
        tot--;
    
        //找到第一个比x小,并且能表示的数字
        for(int i=tot; i>=1; i--)
        {
            if(p[i]!=1&&p[i]!=0)
            {
                for(int j=i; j>=1; j--) p[j]=1;
                break;
            }
        }
    
    
        int res=0;
        for(int i=1; i<tot; i++) res=res+dp[i][1][K];
    
        int sum=1;//高位确定有sum个1
        for(int i=tot-1; i>=1; i--)
        {
            if(p[i]==1)
            {
                res=res+dp[i][0][K-sum];
                sum++;
            }
        }
        sum=0;
        for(int i=1; i<=tot; i++)
            if(p[i]==1) sum++;
        if(sum==K) res++;
        return res;
    }
    
    int main()
    {
        init();
        while(~scanf("%d%d",&L,&R))
        {
            scanf("%d%d",&K,&B);
            printf("%d
    ",f(R)-f(L-1));
        }
        return 0;
    }
  • 相关阅读:
    牛牛的揠苗助长(二分)
    树型DP简单入门
    Rational Ratio(一道思维题)
    Tima goes to Xentopia(条件最短路)
    中国剩余定理
    求解逆元的三种方法
    samba 基本配置及自定义控制
    vue之虚拟DOM、diff算法
    vue-cli3构建ts项目
    VMware+node+nginx+vue
  • 原文地址:https://www.cnblogs.com/zufezzt/p/5168332.html
Copyright © 2020-2023  润新知