zoukankan      html  css  js  c++  java
  • 洛谷 P6218 [USACO06NOV] Round Numbers S

    洛谷 P6218 [USACO06NOV] Round Numbers S

    题目描述

    如果一个正整数的二进制表示中,(0) 的数目不小于 (1) 的数目,那么它就被称为「圆数」。

    例如,(9) 的二进制表示为 (10011001),其中有 (2)(0)(2)(1)。因此,(9) 是一个「圆数」。

    请你计算,区间 ([l,r]) 中有多少个「圆数」。

    输入格式

    一行,两个整数 (l,r)

    输出格式

    一行,一个整数,表示区间 ([l,r])中「圆数」的个数。
    输入输出样例

    输入 #1

    2 12

    输出 #1

    6

    说明/提示

    【数据范围】

    对于 (100\%) 的数据,(1le l,rle 2 imes 10^9)

    【样例说明】

    区间 ([2,12]) 中共有 (6) 个「圆数」,分别为 (2,4,8,9,10,12)

    分析

    比较套路的数位 (DP)

    数位 (DP) 的实质就是换一种暴力枚举的方式,使得新的枚举方式满足 (DP) 的性质,然后记忆化就可以了。

    首先,我们要进行 (DP) 的话,肯定要定义一个 (f) 数组存储我们计算过的值

    因为这道题和数位有关,所以第一位我们要定义当前遍历到了第几位

    而且我们还要判断二进制下 (0) 的数量和 (1) 的数量

    所以,我们设 (f[i][j][k]) 为当前遍历到第 (i) 位,二进制下 (1) 的数量为 (j)(0) 的数量为 (j) 的数的个数

    主函数我们用差分的思想搞一下即可

    signed main(){
    	memset(f,-1,sizeof(f));
    	int l,r;
    	scanf("%lld%lld",&l,&r);
    	printf("%lld
    ",solve(r)-solve(l-1));
    	return 0;
    }
    

    然后是 (solve) 函数

    这里的 (cnt) 是用来记录当前的数在二进制下有多少位,(num) 数组是用来记录这个数每一二进制位上的数字的

    这个函数的变量只有一个 (xx), 返回值是 (0)(xx) 之间圆数的个数

    int solve(int xx){
    	memset(num,0,sizeof(num));
    	cnt=0;
    	while(xx){
    		num[++cnt]=xx&1ll;
    		xx>>=1ll;
    	}
    	return dfs(cnt,0,0,1,1);
    }
    

    下面的 (dfs) 函数是最重要的部分

    int dfs(int ws,int tot1,int tot0,bool lim,bool zer){
    	if(ws==0) {
    		if(tot1<=tot0) return 1;
    		return 0;
    	}
    	if(lim==0 && zer==0 && f[ws][tot1][tot0]!=-1) return f[ws][tot1][tot0];
    	int up=1,ans=0;
    	if(lim) up=num[ws];
    	for(int i=0;i<=up;i++){
    		if(zer==1 && i==0) ans+=dfs(ws-1,0,0,lim && i==up,1);
    		else ans+=dfs(ws-1,tot1+(i==1),tot0+(i==0),lim && i==up,0);
    	}
    	if(lim==0 && zer==0)f[ws][tot1][tot0]=ans;
    	return ans;
    }
    

    它的五个参数分别为:当前处理到第 (ws)

    (0) 的个数 (tot0) ,(1) 的个数 (tot1)

    (lim) 特判前一位是否为范围内的最大值

    (zer) 记录有没有前导零

    终止条件就是处理到最后一位

    具体的边界看一下下面的模板

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    int f[60][60][60],num[55],cnt,sum[55];
    const int mod=1e7+7;
    int dfs(int ws,int tot1,int tot0,bool lim,bool zer){
    	if(ws==0) {
    		if(tot1<=tot0) return 1;
    		return 0;
    	}
    	if(lim==0 && zer==0 && f[ws][tot1][tot0]!=-1) return f[ws][tot1][tot0];
    	int up=1,ans=0;
    	if(lim) up=num[ws];
    	for(int i=0;i<=up;i++){
    		if(zer==1 && i==0) ans+=dfs(ws-1,0,0,lim && i==up,1);
    		else ans+=dfs(ws-1,tot1+(i==1),tot0+(i==0),lim && i==up,0);
    	}
    	if(lim==0 && zer==0)f[ws][tot1][tot0]=ans;
    	return ans;
    }
    int solve(int xx){
    	memset(num,0,sizeof(num));
    	cnt=0;
    	while(xx){
    		num[++cnt]=xx&1ll;
    		xx>>=1ll;
    	}
    	return dfs(cnt,0,0,1,1);
    }
    signed main(){
    	memset(f,-1,sizeof(f));
    	int l,r;
    	scanf("%lld%lld",&l,&r);
    	printf("%lld
    ",solve(r)-solve(l-1));
    	return 0;
    }
    
  • 相关阅读:
    分布式版本控制系统Git的安装与使用
    随笔--第一篇博客
    字符串、文件操作,英文词频统计预处理
    了解大数据的特点、来源与数据呈现方式
    第五次作业-结对项目四则运算 “软件”之升级版
    第四次作业:个人项目-小学四则运算 “软件”之初版
    读《构建之法》1-5章有感
    第二次作业——分布式版本控制系统Git的安装与使用
    第一次作业——感想
    【大数据】字符串、文件操作,英文词频统计预处理
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/13530574.html
Copyright © 2011-2022 走看看