• 数位dp D


    题目:D - Count The Bits

    博客  

     这个题目时给你k,b 让你求从0到2^b-1这些数中有多少个数可以整除k,并求出这个数二进制表示的1的个数

    分析完题目之后就是对数进行处理。

    首先我们要想怎么去定义dp,感觉还是很难想啊,那就想想怎么去处理这些数来满足题目要求

    既然时二进制的表示,那么我们就把这个当作二进制来求所以这个时候枚举就是从0到1,然后我们需要一个数来表示这个二进制中1的个数,还需要一个数来表示这个数的大小

    这样子dp就应该比较好定义了,dp[i][j][k] 第i位,这个数的大小,其中二进制含有1 的个数。

     但是这个数字可以非常大,难道我们就定义一个超级大的数组吗?

    肯定是不可以的,观察题目发现,我们是要求这个数字整除k,

    如果你对于取模足够了解的话,你就会知道,如果我们要判断一个数对某一个数是的余数,我们可以边取模边写这个数字,

    比如说1234 对于4 取模

    那我们先出4 对4取模一次,然后 再是对取模之后的结果 *10 之后加上 3 然后再取模。。。

    所以这个时候这一维度的数字大小就可以降低到k的大小了。

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    #include <queue>
    #define inf 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    const int mod = 1000000009;
    ll dp[130][1010][130]; //dp[i][j][k] 其中i代表第i位,j代表这个数的大小,因为我是要k的倍数,所以对k进行取膜即可,k就是表示这数化成二进制含有1的个数
    int k, b;
    
    ll dfs(int pos,int num,int sum,bool limit)
    {
    	if (pos == -1) return num ? 0 : sum;
    	if (!limit&&dp[pos][num][sum] != -1) return dp[pos][num][sum];
    	ll ans = 0;
    	for(int i=0;i<=1;i++)
    	{
    		ans += dfs(pos - 1, (num * 2 + i) % k, sum + i, limit&&i);
    		ans %= mod;
    	}
    	if (!limit) dp[pos][num][sum] = ans;
    	return ans;
    }
    
    ll solve()
    {
    	return dfs(b - 1, 0, 0, true);
    }
    
    int main()
    {
    	scanf("%d%d", &k, &b);
    	memset(dp, -1, sizeof(dp));
    	printf("%I64d
    ", solve());
    	return 0;
    }
    

      

  • 相关阅读:
    如何获得刚刚插入数据的id
    Ado.net怎么执行存储过程?
    SqlServer存储过程,学习
    视图view
    CTE(公用表表达式)
    事务
    over()的用法
    Inno Setup 系列之安装、卸载前检测进程运行情况并关闭相应进程
    Inno Setup的常用脚本
    跟武哥一起学习Spring Boot
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/10601701.html
Copyright © 2020-2023  润新知