二进制上的数位dpPOJ 3252
Round number POJ - 3252
题目大意:一个"round number" 数的定义是,将它转化成2进制后,0的个数大于等于1的个数,要求的就是在[s,f]范围内"round number"的个数
和之前的数位dp不同的是,这题是对二进制的数位进行dp,所以就存在着一个限制,前面有没有存在1,如果前面没有1.那么像00001,就是1,前面的0是不计数的,所以重点就在于考虑这个dfs时就得分前面有没有1,如果没有那么0就不计数,反之我们记录0和1的差值,取0加1,取1减1,不过需要注意的是,差值可能是负数,所以要转正数,详情见代码
#include<cstdio>
#include<cstring>
#define ll long long
const int N=;
int up[N];
ll n,s,f,dp[N][*N][];//dp[i][j][k]代表当前为第i位,前面0和1的差值为j-N,前面有没有1的结果
//例如dp[4][50][1]就代表第4位,在第4位前面0和1差值为0,并且前面有1的结果数
ll dfs(int p,int d,bool is1,bool isu)//p 位数,d 0和1的差值,is1 该位前面有没有1 isu有没有上限
{
if(!p)//边缘状态,0大于等于1(d>=0)返回1,反之返回0
return d>=;
if(-d>p)//小剪枝,如果剩下位数全是0加起来都没有1多,返回0
return ;
if(!isu&&dp[p][d+N][is1]!=-)
return dp[p][d+N][is1];
ll ans=;
for(int i=;i<=(isu ? up[p] : );i++)
{
if(is1)//当前面有1正常记录0的差值
ans+=dfs(p-,(i ? d- : d+),is1||i,isu&&i==up[p]);
else//当前面没有1,0不计,1记-1
ans+=dfs(p-,-i,is1||i,isu&&i==up[p]);
}
if(!isu)
dp[p][d+N][is1]=ans;
return ans;
}
ll solve(ll x)
{
int num=;
while(x)
{
up[++num]=x&;
x>>=;
}
return dfs(num,,,);
}
int main()
{
ll s,f;
memset(dp,-,sizeof(dp));
while(~scanf("%lld%lld",&s,&f))
printf("%lld\n",solve(f)-solve(s-));
return ;
}
RNGRNGRNG
关于结果的存储,不同的想法具体的dp还有也不同,有些是dp[i][j][k]是当前是第i位,前面0的个数为j,前面1的个数为k的结果有多少个,不过大体的思路还是相同的
除数位dp外,还有一个组合数学的解法,不过相比大佬们,我的思路有点麻烦,详情见代码
#include<cstdio>
#include<cstring>
#define ll long long
ll n,m,c[][]={},a[]={};//c组合数,a[i]长度为i,首位1在第i位存在RN的个数
//比加a[1]保存1,a[2]保存10,11,a[3]保存100,101,110,111,中满足RN的个数
//所以a[1]=0,a[2]=1,a[3]=1
int up[]={};
void init()
{
for(int i=;i<=;i++)
{
c[i][]=;
for(int j=;j<=i;j++)
{
if(j<=i/)
c[i][j]=c[i-][j-]+c[i-][j];
else
c[i][j]=c[i][i-j];
}
for(int j=i-;j>=(i+)/;j--)//首位i是1,剩下i-1位0可以i-1个,
//i-2个,假设最少取j个满足要求,那么j>=(i+1)/2(0的数目大于等于总数目的一半)
a[i]+=c[i-][j];
}
}
ll solve(ll x)
{
int num=;
while(x)
{
up[++num]=x&;
x>>=;
}
ll ans=;
for(int i=;i<num;i++)
ans+=a[i];
//假如x转化成2进制是1101
//先算上1,10~11,100~111的里的答案
if(num>)//先把1000算上
ans++;
int z=;//记录第i位前0的个数
//再来计算1000~1101之间的答案,down代表有没有计算到下界
//一开始的下界就是1000
for(int i=num-,down=;i>=;i--)
{
if(up[i])//当存在1时,例如第二位就是1,我们就求的是1000~1100的答案
{
if(down)//因为之前已经算过1000了,所以这里减去
ans--,down=;
for(int j=i-;z+j+>=(num+)/&&j>=;j--)//假设第i位是0,前面的0加上
//第i位再加上后面取的j个0,总的0的个数要大于等于总个数
ans+=c[i-][j];
if(i-+z>=(num+)/)//假设后面的i-1全是0,0的个数大于等于总个数
ans++,down=;//那么1100可以作为下界
}
else
z++;
}
return ans;
}
int main()
{
init();
while(~scanf("%lld%lld",&n,&m))
printf("%lld\n",solve(m)-solve(n-));
return ;
}
WEWEWE
二进制上的数位dpPOJ 3252的更多相关文章
- 图片的URL上传至阿里云OSS操作(微信小程序二维码返回的二进制上传到OSS)
当我们从网络中获取一个URL的图片我们要存储到本地或者是私有的云时,我们可以这样操作 把url中的图片文件下载到本地(或者上传到私有云中) public String uploadUrlToOss ...
- ftp设置二进制上传
一个不重要的数据库,备份是用expdp导出,然后上传到ftp服务器上面.上周这个主机宕机了,要在别的数据库恢复,发现报如下错误: ORA-39001: invalid argument value O ...
- bzoj 3209 花神的数论题——二进制下的数位dp
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3209 可以枚举 “1的个数是...的数有多少个” ,然后就是用组合数算在多少位里选几个1. ...
- 前端上传图片 base64转二进制上传
var dataURItoBlob = function (dataURI) { var byteString = atob(dataURI.split(',')[1]); var mimeStrin ...
- 浅谈数位DP
在了解数位dp之前,先来看一个问题: 例1.求a~b中不包含49的数的个数. 0 < a.b < 2*10^9 注意到n的数据范围非常大,暴力求解是不可能的,考虑dp,如果直接记录下数字, ...
- BZOJ3329 Xorequ(数位DP)
题目大意:x xor 2x=3x(与x xor 3x=2x等价)求满足等式且小于n的x的个数,与满足等式小于2n的数的个数. 因为异或是不进位的二进制加法,那么因为结果正好和加法相同,那么说明x在二进 ...
- BZOJ 4513: [Sdoi2016]储能表 [数位DP !]
4513: [Sdoi2016]储能表 题意:求\[ \sum_{i=0}^{n-1}\sum_{j=0}^{m-1} max((i\oplus j)-k,0) \] 写出来好开心啊...虽然思路不完 ...
- 【数位DP】题集
1.[HDOJ2089] 题意:求区间内不出现4和62的数的个数 解法:模板题 2.[HDOJ3555] 题意:求区间内不出现49的数的个数 解法:模板题 3.[HDOJ5179] 题意:对于一个十进 ...
- 蒟蒻的数位DP专题总结
BZOJ 1026: [SCOI2009]windy数: 题目链接: http://www.lydsy.com/JudgeOnline/problem.php?id=1026 d ...
随机推荐
- 项目实践 hrm项目的设计过程
人事管理系统的设计过程 一.数据库表和持久化类 1.1 进行需求分析,根据功能模块设计数据库表 1.2 设计持久化实体 面向对象分析,即根据系统需求提取出应用中的对象,将这些对象抽象成类,再抽 ...
- Flask:上下文管理
1. werkzurg from werkzur.serving import run_simple def run(environ,start_response): reuturn [b'hello ...
- Windows 7 系统下显示文件类型的扩展名和隐藏文件
一.显示扩展名 点击开始菜单 在搜索框中输入「文件夹选项」并单击 切换到「查看」栏,取消勾选「隐藏已知文件类型的扩展名」这一项 设置完成 ps: 你也可以通过单击下图位置进行相应操作来达到同样的效果 ...
- vue的使用与安装 npm -v报错
1.先将node从官方文档下载下来,然后进行安装. 安装成功后,在dos命令中node -v.npm -v来测试,如果成功就可以安装cnpm(国内淘宝镜像比较快).这里我遇到一个bug,npm -v压 ...
- win10下当前目录右键添加CMD快捷方式
在某个文件夹下右键打开cmd,这样不用每次都在默认情况下切换目录.无奈win10 1703版本下shift+右键不能打开cmd,只能打开powershell. 首先,在桌面新建一个文本文档. Wind ...
- CentOS7 使用光盘镜像作为yum源
1. 首先,如果是虚拟机,则确认guest有光驱并且处于激活状态,如果是真机则在光驱中插入光盘 :-) 2. mkdir /media/cdrom mount /dev/cdrom /media/c ...
- windows 下Nginx 入门
验证配置是否正确: nginx -t 查看Nginx的版本号:nginx -V 启动Nginx:start nginx 快速停止或关闭Nginx:nginx -s stop 正常停止或关闭Nginx: ...
- raise与raise······from
在python中,如果想手动引发一个异常,我们一般都会使用raise # -*- coding:utf-8 -*- # @Author: WanMingZhu # @Date: 2019/10/22 ...
- 设置本地cookie 存session 保持长期有效
<?php session_start(); // 启动Session $_SESSION['count']; // 注册Session变量Count isset($PHPSESSID)?ses ...
- ssh connection refused 问题
以下内容引用自:ephererid的文章: https://segmentfault.com/a/1190000014532520 问题 在使用ssh连接时出现: $ ssh localhost ss ...