您的位置:首页 > 其它

hdu 4734 F(x) 数位DP裸

2017-10-02 21:53 92 查看

Description

For a decimal number x with n digits (A nA n-1A n-2 … A 2A 1), we define its weight as F(x) = A n * 2 n-1 + A n-1 * 2 n-2 + … + A 2 * 2 + A 1 * 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).

Input

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 < 10 9)

Output

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.

Sample Input

3

0 100

1 10

5 100

Sample Output

Case #1: 1

Case #2: 2

Case #3: 13

这道题是说要求在0到B里有多少个数的F值小于等于F(A),然后我们可以发现这题可以数位DP做,F值的定义是一个数的这一位乘以这一位的2次方

举个例子

1234 = 4 * 1 + 3 * 2 + 2 * 4 + 1 * 8

借这道题写一下数位DP的模板的套路

dfs函数里面传参

dfs( int len, int ... ,int lead, int limit )


有些题会有其他参数,有些题需要传lead,表示是否有前导0,limit通常表示这一位有没有限制,如果有限制的话就应该是这一位的上限,如果没有限制的话就是0-9

在函数里面我们通常是先设计返回的情况,比如len为-1的时候返回这个点是否满足,满足为1,不满足为0,再比如我们记忆化一个dp[i][j],当这个点没有limit限制并且没有前导零限制等各种限制时return这个dp[i][j],否则我们就求一个这一位的up值,表示这一位最大可以取什么,然后for语句取for一些状态然后继续dfs下去,最后在没有限制的情况下把答案赋值给dp数组,也就是记忆化数组里面,最后再return即可,通常我们会在solve函数里面先把数位分解为我们想要的样子放到数组里面,十进制分解,二进制分解等等,放到数组里面,记录长度然后再传入dfs函数中,最后计算得出答案返回到主函数中

这道题其实就是一道裸题,按照上面说的思路来就可以了

#include <bits/stdc++.h>
using namespace std;
int len, dp[11][ 50000 + 10 ], a[25];

int F( int n ) {
int tmp = 0, BASE = 1;
while( n ) {
tmp += n % 10 * BASE;
BASE *= 2;
n /= 10;
}
return tmp;
}

int dfs( int pos, int ans, int flag ) {
if( pos < 0 ) return ans >= 0;
if( ans < 0 ) return 0;
int sum = 0;
if( !flag && dp[pos][ans] != -1 ) return dp[pos][ans];
int up = flag ? a[pos] : 9;
for( register int i = 0; i <= up; i++ ) sum += dfs( pos - 1, ans - i * ( 1 << pos ), flag && i == up );
if( !flag ) dp[pos][ans] = sum;
return sum;
}

int solve( int A, int B ) {
len = 0;
while(B) {
a[len++] = B % 10;
B /= 10;
}
return dfs( len - 1, F(A), 1 );
}

int main( ) { int T, A, B;
scanf( "%d", &T );
memset( dp, -1, sizeof(dp) );
for( register int Emmmm = 1; Emmmm <= T; Emmmm++ ) {
scanf( "%d%d", &A, &B );
printf("Case #%d: %d\n", Emmmm, solve( A, B ) );
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: