URAL 1057 Amount of Degrees 数位dp
2017-06-03 17:12
302 查看
原题链接:URAL 1057 Amount of Degrees
做了前两道数位dp,作者就在想:“数位dp原来这么简单啊,连状态都是一个模式,都是dp[i][j]表示以j开头的i位数字,看来再刷一道题就可以完全学会数位dp了。”
可是这道题目现场打脸,orz,一点思路都没有,用前两道类似的状态根本无法解决此题。直到看了大神的论文才知道数位dp的水原来这么深(可能只是本渣觉得深),以后还是老老实实刷题吧。
论文链接:算法合集之《浅谈数位类统计问题》
相信看了一遍之后就可以明白大概的意思了。不过读者可能对一个地方还是心存疑惑,那就是非二进制怎么处理?为什么论文中的方法是正确的呢?
先看下面这幅图
![](https://img-blog.csdn.net/20170603165736250?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvRUNOVV9MWko=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
这是三进制的情况下的完全三叉树,显而易见,节点数字>1的都是不合理的,因为最后答案用3进制表示肯定都是0和1。
当我们把不合理的树“剪”了之后,发现剩下的树就是完全二叉树!
回顾一下论文中的处理方式:从高位到低位查找,碰到第一个非0、1的数字时,将该位数字及其右边的所有数字全部变成1,然后按照二进制的方法来处理。
比如三进制表示的数字021,按照上述方法就变成了011。可以看得出来这是最贴近021的合法数字,这样处理之后保证了符合条件的数字都小于等于011,所以这种处理是正确的。其实这么说可能还是有点抽象,仔细的看图理解一下说不定更容易懂。
代码如下:
做了前两道数位dp,作者就在想:“数位dp原来这么简单啊,连状态都是一个模式,都是dp[i][j]表示以j开头的i位数字,看来再刷一道题就可以完全学会数位dp了。”
可是这道题目现场打脸,orz,一点思路都没有,用前两道类似的状态根本无法解决此题。直到看了大神的论文才知道数位dp的水原来这么深(可能只是本渣觉得深),以后还是老老实实刷题吧。
论文链接:算法合集之《浅谈数位类统计问题》
相信看了一遍之后就可以明白大概的意思了。不过读者可能对一个地方还是心存疑惑,那就是非二进制怎么处理?为什么论文中的方法是正确的呢?
先看下面这幅图
这是三进制的情况下的完全三叉树,显而易见,节点数字>1的都是不合理的,因为最后答案用3进制表示肯定都是0和1。
当我们把不合理的树“剪”了之后,发现剩下的树就是完全二叉树!
回顾一下论文中的处理方式:从高位到低位查找,碰到第一个非0、1的数字时,将该位数字及其右边的所有数字全部变成1,然后按照二进制的方法来处理。
比如三进制表示的数字021,按照上述方法就变成了011。可以看得出来这是最贴近021的合法数字,这样处理之后保证了符合条件的数字都小于等于011,所以这种处理是正确的。其实这么说可能还是有点抽象,仔细的看图理解一下说不定更容易懂。
代码如下:
#include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <cmath> using namespace std; typedef long long int ll; int dp[35][35]; ll X, Y, K, B; void init() { memset(dp, 0, sizeof(dp)); dp[0][0] = 1; for (int i = 1; i <= 31; i++) { dp[i][0] = 1; for (int j = 1; j <= i; j++) dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1]; } } // 计算[0, n)中有多少个二进制含有K个1的数字 int cal(ll x) { int ans = 0, tot = 0; for (int i = 31; i>= 1; i--) { if (x & (1 << i)) { tot++; if (tot > K) break; x ^= (1 << i); } if ((1 << (i - 1)) <= x) ans += dp[i - 1][K - tot]; } return ans; } // 将b进制的情况转化成2进制 ll change(ll x) { int digit[35] = {0}, len = 0; while (x) { digit[++len] = x % B; x /= B; } int high = len; while (high >= 1 && digit[high] <= 1) high--; for (int i = high; i >= 1; i--) digit[i] = 1; ll res = 0; for (int i = len; i >= 1; i--) res = res * 2 + digit[i]; return res; } int main() { //freopen("test.txt", "r", stdin); init(); while (~scanf("%lld%lld%lld%lld", &X, &Y, &K, &B)) { ll x = change(X); ll y = change(Y); printf("%d\n", cal(y + 1) - cal(x)); } return 0; }
相关文章推荐
- URAL 1057 Amount of Degrees (数位DP)
- URAL 1057 Amount of Degrees(数位DP)
- ural1057 Amount of Degrees ——数位DP
- [URAL1057]Amount of Degrees(数位dp)
- URAL 1057 Amount of Degrees (数位dp)
- ural1057 Amount of Degrees 数位dp
- 【URAL 1057】 Amount of Degrees 【数位DP】
- URAL 1057 Amount of Degrees 数位DP *
- ural 1057 Amount of Degrees(数位dp)
- ural 1057 Amount of degrees (数位dp)
- Ural 1057 Amount of Degrees【数位Dp】
- ural1057 Amount of Degrees 【数位dp】论文例题
- URAL - 1057 Amount of Degrees--数位dp
- 【数位DP】URAL 1057 Amount of Degrees
- URAL 1057 Amount of Degrees(数位dp)
- Ural 1057 Amount of Degrees(数位DP)
- [数位dp] ural 1057 Amount of Degrees
- 数位DP-URAL-1057-Amount of Degrees
- Ural1057 - Amount of Degrees(数位DP)
- ural 1057 Amount of degrees 数位DP (入门)