zoukankan      html  css  js  c++  java
  • [poj3252]Round Numbers_数位dp

    Round Numbers poj3252

        题目大意:求一段区间内Round Numbers的个数。

        注释:如果一个数的二进制表示中0的个数不少于1的个数,我们就说这个数是Round Number.给定区间l,r<=$2cdot 10^9$。

          想法:又是一道数位dp裸题。我们先来设状态:dp[i]表示二进制表示下有i为而且第一位是1的Round Number的个数。

            这题的特殊之处在于我们并不需要转移?因为我们可以直接求出任意的dp[i]。显然,我们的i位数的第一位是1,所以,后面0的个数一定不能少于(i-1)/2+1.我们在后面的i-1位当中去组合数即可。

          然后,我们思考数位dp的边界:对于一个数来讲,我们可以将所有的位数小于tot的dp全部加起来(tot是该数的二进制表示下的位数)。然后,我们显然只需要对于这个数的二进制从左到右枚举:弄两个计数器分别记录之前经过了多少个0.对于当前数码,如果是0,略过即可。如果是1,则在它之后所有满足该位是0前面满足的数的Round Number都是满足条件的Round Number。,统计即可。

        最后,附上丑陋的代码... ...

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    int C[33][33];
    void before_hand()//预处理组合数
    {
    	C[0][0]=1;
    	C[1][0]=1;C[1][1]=1;
    	for(int i=2;i<33;i++)
    	{
    		C[i][0]=1;
    		for(int j=1;j<i;j++)
    			C[i][j]=C[i-1][j-1]+C[i-1][j];
    		C[i][i]=1;
    	}
    }
    int bits[33];
    int dispose(int n)
    {
    	if(n<=1) return 0;
    	int tot=0;
    	while(n>0)//二进制拆分
    	{
    		if(n&1) bits[tot++]=1;
    		else bits[tot++]=0;
    		n>>=1;
    	}
    	int ans=0;
    	for(int i=tot-1;i>0;i--)//将位数小于tot的全部加一起
    	{
    		if(i%2==0)
    			ans+=((1<<(i-1)))/2;
    		else
    			ans+=((1<<(i-1))-C[i-1][(i-1)/2])/2;
    	}
    	int count_for_0=0,count_for_1=0;//两个计数器(字面意思)
    	for(int i=0;i<tot;i++)
    	{
    		if(bits[i]==0) count_for_0++;
    		else count_for_1++;
    	}
    	if(count_for_0>=count_for_1) ans++;
    	count_for_0=0;
    	count_for_1=1;
    	for(int i=tot-2;i>=0;i--)
    	{
    		if(bits[i]==1)
    		{
    			for(int j=i;j>=0&&j+count_for_0+1>=i-j+count_for_1;j--)
    				ans+=C[i][j];//简单点儿来说就是直接统计后面的dp值
    			count_for_1++;
    		}
    		else count_for_0++;//如果是0,就直接增加计数器
    	}
    	return ans;
    }
    
    int main()
    {
    	before_hand();
    	int a,b;
    	while(scanf("%d%d",&a,&b)!=EOF)
    	{
    		printf("%d
    ",dispose(b)-dispose(a-1));//防止重叠
    	}
    	return 0;
    }
    

         小结:数位dp的恶心之处就是边界特判,沉下心来写一写,不行就把代码拿去copy算了,毕竟这道题的本质不是代码... ...

  • 相关阅读:
    Java编程思想读书笔记 第十章 内部类
    利用lambda和条件表达式构造匿名递归函数
    概率论与数理统计-课程小报告
    leetcode226 翻转二叉树
    leetcode199 二叉树的右视图
    leetcode114- 二叉树展开为链表
    leetcode145 二叉树的后序遍历 特别注意迭代
    leet144 二叉树的前序遍历
    leetcode113 路径总和2 特别关注
    leetcode 112 路径总和 特别关注
  • 原文地址:https://www.cnblogs.com/ShuraK/p/8560401.html
Copyright © 2011-2022 走看看