HDU 4734 F(x) (数位DP)
2016-07-20 16:56
375 查看
原题地址:传送门 http://acm.hdu.edu.cn/showproblem.php?pid=4734
Total Submission(s): 3771 Accepted Submission(s): 1399
[align=left]Problem Description[/align]
For a decimal number x with n digits (AnAn-1An-2 ... A2A1), we define its weight as F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2
* 2 + A1 * 1. Now you are given two numbers A and B, please calculate how many numbers are there between 0 and B, inclusive, whose weight is no more than F(A).
[align=left]Input[/align]
The first line has a number T (T <= 10000) , indicating the number of test cases.
For each test case, there are two numbers A and B (0 <= A,B < 109)
[align=left]Output[/align]
For every case,you should output "Case #t: " at first, without quotes. The
t is the case number starting from 1. Then output the answer.
[align=left]Sample Input[/align]
3
0 100
1 10
5 100
[align=left]Sample Output[/align]
Case #1: 1
Case #2: 2
Case #3: 13
这个题比较新颖,题目大意就是,定义一个 f(x) 等于它的各个位数乘以该位对应的二进制权值。
比如,f( 492 ) = 4*2^2 + 9*2^1 + 2*2^0
给定一个a,和一个b
求区间 [ 1 , b ] 内,f(x) 不大于 f(a) 的数的个数。
仔细看看就能发现是数位DP,而且也不太难处理。
先求出 f(a) 的值
在搜索的时候,一个参数代表与 f(a) 的差值。
更新维护时,就是差值再减去新的位数乘以它的权值。
再搜索下一层。
根据数据范围,f(x) 最大的应该为999999999。他的 f(x) 为 (1+2+4+8+16+32+64+128+256)*9 = 4599
dp [ 20 ] [ 5000 ] 代表数位和与 f(a) 的差值
int dfs(int pos,int pre,bool limit) 处理数位,与 f(a) 的差值,界限。
最后如果差值大于等于0,那么就返回1。
下面贴代码:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std;
int dp[20][5000];
int digit[20];
int dfs(int pos,int pre,bool limit)
{
if(pos==-1)
{
return pre>=0;
}
if(pre<0)
{
return 0;
}
if(!limit&&dp[pos][pre]!=-1)
{
return dp[pos][pre];
}
int res=0;
int tmp=limit? digit[pos]:9;
for(int i=0; i<=tmp; i++)
{
res+=dfs(pos-1,pre-i*(1<<pos),limit&&i==tmp);
}
if(!limit)
{
dp[pos][pre]=res;
}
return res;
}
int F(int x)
{
int ret = 0;
int len = 0;
while(x)
{
ret += (x%10)*(1<<len);
len++;
x /= 10;
}
return ret;
}
int a,b;
int cal(int b)
{
int len=0;
while(b)
{
digit[len++]=b%10;
b=b/10;
}
return dfs(len-1,F(a),1);
}
int main()
{
int t,cake=1;
scanf("%d",&t);
memset(dp,-1,sizeof(dp));
while(t--)
{
scanf("%d%d",&a,&b);
printf("Case #%d: %d\n",cake++,cal(b));
}
return 0;
}
F(x)
Time Limit: 1000/500 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3771 Accepted Submission(s): 1399
[align=left]Problem Description[/align]
For a decimal number x with n digits (AnAn-1An-2 ... A2A1), we define its weight as F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2
* 2 + A1 * 1. Now you are given two numbers A and B, please calculate how many numbers are there between 0 and B, inclusive, whose weight is no more than F(A).
[align=left]Input[/align]
The first line has a number T (T <= 10000) , indicating the number of test cases.
For each test case, there are two numbers A and B (0 <= A,B < 109)
[align=left]Output[/align]
For every case,you should output "Case #t: " at first, without quotes. The
t is the case number starting from 1. Then output the answer.
[align=left]Sample Input[/align]
3
0 100
1 10
5 100
[align=left]Sample Output[/align]
Case #1: 1
Case #2: 2
Case #3: 13
这个题比较新颖,题目大意就是,定义一个 f(x) 等于它的各个位数乘以该位对应的二进制权值。
比如,f( 492 ) = 4*2^2 + 9*2^1 + 2*2^0
给定一个a,和一个b
求区间 [ 1 , b ] 内,f(x) 不大于 f(a) 的数的个数。
仔细看看就能发现是数位DP,而且也不太难处理。
先求出 f(a) 的值
在搜索的时候,一个参数代表与 f(a) 的差值。
更新维护时,就是差值再减去新的位数乘以它的权值。
再搜索下一层。
根据数据范围,f(x) 最大的应该为999999999。他的 f(x) 为 (1+2+4+8+16+32+64+128+256)*9 = 4599
dp [ 20 ] [ 5000 ] 代表数位和与 f(a) 的差值
int dfs(int pos,int pre,bool limit) 处理数位,与 f(a) 的差值,界限。
最后如果差值大于等于0,那么就返回1。
下面贴代码:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std;
int dp[20][5000];
int digit[20];
int dfs(int pos,int pre,bool limit)
{
if(pos==-1)
{
return pre>=0;
}
if(pre<0)
{
return 0;
}
if(!limit&&dp[pos][pre]!=-1)
{
return dp[pos][pre];
}
int res=0;
int tmp=limit? digit[pos]:9;
for(int i=0; i<=tmp; i++)
{
res+=dfs(pos-1,pre-i*(1<<pos),limit&&i==tmp);
}
if(!limit)
{
dp[pos][pre]=res;
}
return res;
}
int F(int x)
{
int ret = 0;
int len = 0;
while(x)
{
ret += (x%10)*(1<<len);
len++;
x /= 10;
}
return ret;
}
int a,b;
int cal(int b)
{
int len=0;
while(b)
{
digit[len++]=b%10;
b=b/10;
}
return dfs(len-1,F(a),1);
}
int main()
{
int t,cake=1;
scanf("%d",&t);
memset(dp,-1,sizeof(dp));
while(t--)
{
scanf("%d%d",&a,&b);
printf("Case #%d: %d\n",cake++,cal(b));
}
return 0;
}
相关文章推荐
- 封装好的Folyd建图,C++源码
- matlab与c/c++混合编程
- matlab与c/c++混合编程——c/c++调用matlab
- TYVJ1193 括号序列解题报告
- TYVJ上一些DP的解题报告
- C/C++常用的调试宏
- VC内存泄露检查工具:VisualLeakDetector
- 内联函数总结
- usb体系结构
- VC结构体实现类似数组的下标操作符功能
- C/C++ 嵌套结构体动态内存管理实现
- C++调用gSoap编写的WEBSERVICE与C#.NET间接口自定义结构体不能重复使用
- 处理VC开发的webservice在C#.NET中中文乱码问题
- gcc使用入门
- C/C++ Linux 程序员必须了解的 10 个工具
- 递归遍历数组
- 用C/C++打印*号图案
- C++之四书五经(上)
- C++中const的使用
- *p++和*++p的区别