数位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表示贫瘠,把牛放在肥沃处,要求所有牛不能相 ...
随机推荐
- python数据结构与算法第十一天【希尔排序】
1.希尔排序的原理 2.代码实现 def shell_sort(alist): n = len(alist) # 初始步长 gap = n / 2 while gap > 0: # 按步长进行插 ...
- Bootstrap之表格、表单应用
代码: <!DOCTYPE html> <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml&q ...
- Auth模块使用方法大全
auth认证 导包 from django.contrib import auth 默认数据库中使用auth_user表 创建超级用户 python manage.py createsuperuser ...
- python---反射详解
反射即想到4个内置函数分别为:getattr.hasattr.setattr.delattr 获取成员.检查成员.设置成员.删除成员 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ...
- HTC Vive 基础入门 基于Unity3D引擎
任务2: 01-概述 07:08 任务3: 02-HTC Vive设备的安装 08:33 任务4: 03-下载Steam与SteamVR 03:05 任务5: 04-使用Steam VR 调试设备 1 ...
- 洛谷P1216数字三角形题解
题目 这道题是一个典型的DP,可以用倒推,顺推的方法,来解这道题.当然用不同的方法他的循环次序是不一样的,所以我们一定要深刻地理解题目的大意,再采用状态转移方程与边界每次求出最优解,并记录循环一遍后就 ...
- 序列化模块组 pickle,json , xml , shelve , configparser
序列化是什么? 序列化指的是将内存中的数据结构转化为一种中间格式 并存储到硬盘上. 反序列化是什么? 将硬盘上存储的中间格式数据再还原为内存中的数据结构. 为什么要有序列化? 是为了将数据持久存储 较 ...
- Scrapy突破反爬虫的限制
随机切换UserAgent https://github.com/hellysmile/fake-useragent scrapy使用fake-useragent 在全局配置文件中禁用掉默认的UA,将 ...
- 【HDU 4343】Interval query(倍增)
BUPT2017 wintertraining(15) #8D 题意 给你x轴上的N个线段,M次查询,每次问你[l,r]区间里最多有多少个不相交的线段.(0<N, M<=100000) 限 ...
- Mysql 数据备份导出
mysqldump导出整个数据库mysqldump --single-transaction --skip-lock-tables -uDBUSER -pDBPASSWD -hDBIP \--defa ...