您的位置:首页 > 编程语言 > C语言/C++

HDU 4734 F(x) (数位DP)

2016-07-20 16:56 375 查看
原题地址:传送门  http://acm.hdu.edu.cn/showproblem.php?pid=4734

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;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息