数位DP入门题
站点一览:
- hdu 2089"不要62"
- hdu 4734"F(X)"
- poj 3252"Round Numbers"
- hdu 3709"Balanced Number"
题解:
题目过于简单,不再赘述。
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a)) int a,b;
int digit[];
int dp[][];//dp[i][0]:位置i的前一个位置不为6的总方案数;dp[i][1]正好相反 int DFS(int curPos,int preNum,int isSix,bool limit)
{
if(curPos == -)
return ;
if(!limit && dp[curPos][isSix] != -)
return dp[curPos][isSix]; int up=limit ? digit[curPos]:;
int ans=;
for(int i=;i <= up;++i)
{
if((preNum == && i == ) || i == )
continue;
ans += DFS(curPos-,i,i == ,limit&& i == digit[curPos]);
}
if(!limit)
dp[curPos][isSix]=ans;
return ans;
}
int Solve(int x)
{
int k=;
while(x)
{
digit[k++]=x%;
x /= ;
}
return DFS(k-,,,true);
} int main()
{
while(~scanf("%d%d",&a,&b) && a+b)
{
mem(dp,-);
printf("%d\n",Solve(b)-Solve(a-));
}
return ;
}
Problem Description
For a decimal number x with n digits (AnAn-1An- ... A2A1), we define its weight as F(x) = An * 2n- + An- * 2n- + ... + A2 * + A1 * .
Now you are given two numbers A and B, please calculate how many numbers are there between and B, inclusive, whose weight is no more than F(A). Input
The first line has a number T (T <= ) , indicating the number of test cases.
For each test case, there are two numbers A and B ( <= A,B < ) Output
For every case,you should output "Case #t: " at first, without quotes. The t is the case number starting from . Then output the answer.
题解:
初始想法:
定义dp[ i ][ j ] : [ 0,i ] 位置满足 weight == j 的数的总个数;
求出F(a)后,便利 i : 0~F(a) ,求出 [0,b] weight == i 的数的总个数,作加和;
很不幸,TLE,不过,还是挺开心的,毕竟是在看题解前按照自己的想法成功敲出的代码,虽然TLE了;
正解:定义dp[ i ][ j ] : [ 0,i ]位置满足 weight <= j 的数的总个数,然后,每次判断 dp[ i ][ j ]是否可以直接返回;
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a)) int a,b;
int power[]={,,,,,,,,};
int digit[];
int dp[][];//dp[i][j]:前i位F值小于等于j的总个数 int F(int x)
{
int sum=;
int base=;
while(x)
{
sum += (x%)*base;
base <<= ;
x /= ;
}
return sum;
}
int DFS(int need,int curPos,int curSum,bool limit)
{
if(curPos == -)
return curSum <= need ? :; if(curSum > need)
return ; if(!limit&&dp[curPos][need-curSum] != -)
return dp[curPos][need-curSum]; int up=limit ? digit[curPos]:;
int ans=;
for(int i=;i <= up;++i)
ans += DFS(need,curPos-,curSum+i*power[curPos],limit&&i==digit[curPos]); if(!limit)
dp[curPos][need-curSum]=ans; return ans;
}
int Solve(int x)
{
int k=;
while(x)
{
digit[k++]=x%;
x /= ;
}
int f=F(a);
return DFS(f,k-,,true);
}
int main()
{
int test;
scanf("%d",&test);
mem(dp,-);
for(int kase=;kase <= test;++kase)
{
scanf("%d%d",&a,&b);
printf("Case #%d: %d\n",kase,Solve(b));
}
return ;
}
题意:
输入两个十进制正整数a和b,求闭区间 [a ,b] 内有多少个Round number
所谓的Round Number就是把一个十进制数转换为一个无符号二进制数,若该二进制数中0的个数大于等于1的个数,则它就是一个Round Number
注意,转换所得的二进制数,最高位必然是1,最高位的前面不允许有0
题解:
定义dp[ i ][ j ][ k ] : 在没有限制的情况下,[0,i]位置满足 0 的个数等于 j,1 的个数等于 k 的数的总个数;
坑点:前导零不能算在 0 的总个数中;
因为poj炸了,所以一直处于wait状态,不过对拍了一下他人的AC代码,正确率是可以保证的,应该也不会超时吧orz;
wait代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a)) int a,b;
int digit[];
int dp[][][]; //isSat:只有当出现第一个不为0的位数时才为true
//作用是去掉前导0的影响
int DFS(int curPos,int totZero,int totOne,bool isSat,bool limit)
{
if(curPos == -)
return totZero >= totOne; if(!limit && dp[curPos][totZero][totOne] != -)
return dp[curPos][totZero][totOne]; int up=limit ? digit[curPos]:;
int ans=;
for(int i=;i <= up;++i)
{
bool flag=(isSat || i != );
ans += DFS(curPos-,totZero+(flag&&i==),totOne+(i==),flag,limit&&i==digit[curPos]);
}
if(!limit)
dp[curPos][totZero][totOne]=ans;
return ans;
}
int Solve(int x)
{
int k=;
while(x)
{
digit[k++]=x%;
x >>= ;
}
return DFS(k-,,,false,true);
}
int main()
{
mem(dp,-);
while(~scanf("%d%d",&a,&b))
printf("%d\n",Solve(b)-Solve(a-)); return ;
}
题意:
给一个很大的区间[x,y],(0 ≤ x ≤ y ≤ 1018).问:区间里面的数满足如下规则的有多少个?
规则:将数字放在天平上,天平能够平衡。天平的轴随意,力臂就是数字下标到天平轴的下标的距离。
题解:
脑海中浮现出如何记忆化搜索的代码,可就是没想到如何判断当前数是否为"balance number",无奈之下,查阅大佬代码orz;
坑点:全为0的数会重复计算,需要减去重复的部分
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a)) ll a,b;
int digit[];
ll dp[][][]; //curSum:记录curPivot左边的和+右边的和,只有curSum == 0才能说明
// curPivot左边的和==右边的和
ll DFS(int curPos,int curPivot,int curSum,bool limit)
{
if(curPos == -)
return curSum == ? :;
if(curSum < )
return ;
if(!limit && dp[curPos][curPivot][curSum] != -)
return dp[curPos][curPivot][curSum]; int up=limit ? digit[curPos]:;
ll ans=;
for(int i=;i <= up;++i)
ans += DFS(curPos-,curPivot,curSum+i*(curPos-curPivot),limit&&i==digit[curPos]); if(!limit)
dp[curPos][curPivot][curSum]=ans;
return ans;
}
ll Solve(ll x)
{
if(x == -)
return ;
int k=;
while(x)
{
digit[k++]=x%;
x /= ;
}
ll ans=;
for(int i=k-;i >= ;--i)
ans += DFS(k-,i,,true);
return ans-k+;
//0个0,1个0,.......,(k-1)个0,全为0的情况被记录了k次,须减去(k-1)个重复的
}
int main()
{
int test;
scanf("%d",&test);
mem(dp,-);
while(test--)
{
scanf("%lld%lld",&a,&b);
printf("%lld\n",Solve(b)-Solve(a-));
}
return ;
}
数位DP入门题的更多相关文章
- HDU 2089 不要62【数位DP入门题】
不要62 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
- HDU 2089 - 不要62 - [数位DP][入门题]
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2089 Time Limit: 1000/1000 MS (Java/Others) Memory Li ...
- 数位DP入门题——[hdu2089]不要62
数位DP是我的噩梦. 现在初三了,却没AC过数位DP的题目. 感觉数位DP都是毒瘤-- 题目 hdu不用登录也可以进去,所以就不把题目copy到这里来了. 题目大意 求区间[n,m][n,m][n,m ...
- 【数位dp】【HDU 3555】【HDU 2089】数位DP入门题
[HDU 3555]原题直通车: 代码: // 31MS 900K 909 B G++ #include<iostream> #include<cstdio> #includ ...
- hdu 2089 数位dp入门题
#include<stdio.h> //dp[i][0]代表不存在不吉利数字 //dp[i][1]代表不存在不吉利数字但是以2开头 //dp[i][2]代表存在不吉利数字 #define ...
- hdu3555 Bomb (数位dp入门题)
Bomb Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)Total Submi ...
- xbz分组题B 吉利数字 数位dp入门
B吉利数字时限:1s [题目描述]算卦大湿biboyouyun最近得出一个神奇的结论,如果一个数字,它的各个数位相加能够被10整除,则称它为吉利数.现在叫你计算某个区间内有多少个吉利数字. [输入]第 ...
- 数位dp入门 hdu2089 不要62
数位dp入门 hdu2089 不要62 题意: 给定一个区间[n,m] (0< n ≤ m<1000000),找出不含4和'62'的数的个数 (ps:开始以为直接暴力可以..貌似可以,但是 ...
- poj 3254 状压dp入门题
1.poj 3254 Corn Fields 状态压缩dp入门题 2.总结:二进制实在巧妙,以前从来没想过可以这样用. 题意:n行m列,1表示肥沃,0表示贫瘠,把牛放在肥沃处,要求所有牛不能相 ...
随机推荐
- 微服务架构中APIGateway原理
背景 我们知道在微服务架构风格中,一个大应用被拆分成为了多个小的服务系统提供出来,这些小的系统他们可以自成体系,也就是说这些小系统可以拥有自己的数据库,框架甚至语言等,这些小系统通常以提供 Rest ...
- python易混易乱(1)
字典 基础操作 <1>keys my_dict = {"name":"zhangsan","age":18} res = my_ ...
- python之if使用方法举例
if使用方法举例: import random #随机生成1-100的整数 n = random.randint(1, 100) if n > 50: print(n, "> 5 ...
- layui 提交表格不验证
form.on('submit(filter_save)', function (data) { 后面查找发现是提交按钮要放在form里面
- SELECT IDENT_CURRENT(tableName)和自增长列的纠结
项目中要用到一个功能:主表主键为自增长,要求在插入主表数据前先获得主表要插入数据的主键ID值,用在插入子表时获取主键ID.在网上搜了一下,发现SELECT IDENT_CURRENT(TableNam ...
- npm火速上手
npm,即node package manager,翻译过来就是“node包管理工具”.“node包”是啥呢?它就是jquery啦.bootstrap啦之类的各种版本. 1.npm的安装 第一步,下 ...
- mybatis,主键返回指的是返回到传入的对象中
- struts2 核心过滤器的配置
<!-- struts2 过滤器核心配置--> <filter> <filter-name>struts2</filter-name> <filt ...
- ftell 的使用
ftell一般用于读取文件的长度,下面补充一个例子,读取文本文件中的内容: #include <stdio.h> #include <stdlib.h> int main() ...
- 慢腾腾的Quartus prime16.0加快编译速度
前言 当一个工程反复修改的时候,可能有时候源代码没有更改,为了加快编译速度可以配置quartus一些选项.当然,初次编译的速度是否会提升,未验证.更高级的设计分区以及逻辑锁区提升速度,以后阐述. 流程 ...