Round Numbers(数位dp)

墨蓝 2022-02-19 03:39 359阅读 0赞

题目链接:

http://poj.org/problem?id=3252

分析:

本题我一开始思路便存在一定问题。
其实我们可以把每个数直接化成二进制保存在一个数组里面。通过改变数组里面0或者1的值便可以得到n以内的所有的数。然后,还需要注意一点,就是前导0的存在。 前导0 是不计入最后的比较环节的。 这是一点要注意的。
参考博客:https://blog.csdn.net/jk211766/article/details/81474632

  1. #include"stdio.h"
  2. #include"string.h"
  3. #include"algorithm"
  4. using namespace std;
  5. #define scanll(a,b) scanf("%lld%lld",&a,&b);
  6. typedef long long ll;
  7. ll dp[110][100];
  8. ll digit[20];
  9. /*int check(ll num)
  10. {错误代码思路
  11. int cnt1=0;
  12. int cnt0=0;
  13. if(num == 0) return 0;
  14. while(num)
  15. {
  16. if(num%2==0) cnt0++;
  17. else cnt1++;
  18. num=num/2;
  19. }
  20. return cnt0 >= cnt1;
  21. }*/
  22. int dfs(int pos, ll cnt0,int lead,int limit)
  23. {
  24. if(-1 == pos) return cnt0>=32;
  25. //每次记忆化时,也要判断前导0 如果存在前导0 是不可以直接返回的。
  26. if(!limit && !lead &&dp[pos][cnt0] != -1) return dp[pos][cnt0];
  27. ll cnt = 0;
  28. ll up = limit ? digit[pos] : 1;
  29. for(int i = 0; i <= up; i ++)
  30. {
  31. if(lead && i == 0)
  32. cnt += dfs(pos - 1,cnt0,lead,limit && i == digit[pos]);
  33. else
  34. cnt += dfs(pos - 1,cnt0 + (i == 0 ? 1 : -1),lead && i ==0,limit && i == digit[pos]);
  35. }
  36. //同理,存在前导0 不可以直接记录
  37. if(!limit && !lead ) dp[pos][cnt0] = cnt;
  38. return cnt;
  39. }
  40. int solve(ll num)
  41. {
  42. int k=0;
  43. while(num)//化为二进制保存
  44. {
  45. digit[k++] = num % 2;
  46. num = num / 2;
  47. }
  48. return dfs(k - 1,32,1,1);
  49. }
  50. int main()
  51. {
  52. ll n,m;
  53. scanll(n,m);
  54. memset(dp, -1 ,sizeof(dp));
  55. if(m == 1)
  56. printf("%lld\n",solve(m));
  57. else
  58. printf("%lld\n",(ll)solve(m) - solve(n-1));
  59. }

发表评论

表情:
评论列表 (有 0 条评论,359人围观)

还没有评论,来说两句吧...

相关阅读