• 0和1的熟练


    题目描述
    有一个程序员,他使用只有两个按键的键盘打字。这两个按键就是0和1,只有达到高端境界的人才能出入此境。记住,只有从l到r的所有数都手打过一遍了才能练就如此功夫。作为真正的高手,你一定能快速地回答区间[l,r]中有多少数字的二进制表示(不含前导零)中0的个数不少于1的个数,因为你每天都进行一遍这个练习。

    输入格式
    输入一行两个正整数l和r,表示闭区间的左右端点。
    输出格式
    输出一个整数表示所求答案。
    样例
    样例输入
    2 12
    样例输出
    6
    数据范围与提示
    1<=l<r<=2e9

    数据范围是2e9那么显然美剧是不可以的(废话,要你说)所以就需要换一种方法,有一种神仙做法叫数位DP (优化暴力枚举)
    既然是DP,那么就一定会涉及到状态定义,数位本质就是枚举位数,每一位数字。基本思想就是逐位确定(暴力枚举)
    回到正题,首先我们先确定数位DP的状态。基本思想知道后,定义f[i][0/1][j],表示枚举到第i位,(枚举的是二进制位),其中0的个数减去1的个数为j的方案数。然后就是DP的裸题……
    如果不知道什么是数位DP,看这个
    然后做数位DP基础题看这个,这个是有代码的,还有解释……

    代码奉上:

    #include <bits/stdc++.h>
    using namespace std;
    int k,b,base,maxn;
    int a[100];
    int f[100][100][100];
    int DP(int n,int a[]){
    	memset(f,0,sizeof(f));
    	base=n;
    	f[1][3][base+1]=1;
    	maxn=base+n;
    	for(int i=2;i<=n;++i){
    		for(int j=0;j<maxn;++j){
    			if(f[i-1][0][j]){
    				f[i][0][j-1]+=f[i-1][0][j];
    				f[i][0][j+1]+=f[i-1][0][j];
    			}
    			if(f[i-1][4][j]){
    				if(a[i]){
    					f[i][0][j-1]+=f[i-1][5][j];
    					f[i][6][j+1]+=f[i-1][7][j];
    				}else f[i][8][j-1]+=f[i-1][9][j];
    			}
    		}
    	}
    	int ans=0;
    	for(int i=0;i<=base;++i)ans+=f[n][0][i]+f[n][10][i];
    	return ans;
    }
    int Cala(int x){
    	if(!x)return 0;
    	int n=0;
    	while(x)a[++n]=(x&1),x>>=1;
    	reverse(a+1,a+n+1);
    	int ans=DP(n,a);
    	for(int i=1;i<n;++i)a[i]=1;
    	while(--n)ans+=DP(n,a);
    	return ans;
    }
    int main(){
    	cin>>k>>b;
    	cout<<Cala(b)-Cala(k-1);
    	return 0;
    }
    
  • 相关阅读:
    poj 1067||hdu 1527 取石子游戏(博弈论,Wythoff Game)
    CGAffineTransform属性
    自定义UITabBarController
    UISwitch用法:
    UIButton常见属性和方法
    xcode添加背景音乐/音效
    使用cocoaPods加载框架的具体步骤:
    UILabel
    NSString -- UILabel中字体有多种颜色,字符串自动计算高度/换行
    xcode 修改类名 变量名
  • 原文地址:https://www.cnblogs.com/gdxzq/p/13463570.html
Copyright © 2020-2023  润新知