HDU 4734 (数位DP)

F(x)

Time Limit: 1000/500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3315    Accepted Submission(s): 1247


Problem 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
 


题意:求出区间中所有权值小于给定数的个数.

假设dp(i,j)表示i位权值不超过j的个数,然后就可以得到转移方程:

dp(i,j)=dp(i-1,j+x*10^(i-1))(0<=x<=9)

然后数组的初始化只要一次就好了.

<pre style="font-family: 'Courier New'; background-color: rgb(244, 251, 255);">
<pre name="code" class="cpp">#include <bits/stdc++.h>
using namespace std;
#define mod 1000000007
#define maxn 22

long long a, b;
int bit[maxn], l;
int dp[9][211111];
#define pow Pow
long long pow[maxn];
int sum;

long long dfs (int pos, int m1, bool f2) {
    //当前的位数 之后的权值不能大于m1 是不是可以取到9
    if (pos == 0) { //cout << num << ".." << endl;
        return m1 >= 0;
    }
    if (f2 && dp[pos][m1] != -1) {
        return dp[pos][m1];
    }
    long long Max = (f2 ? 9 : bit[pos]);
    long long ans = 0;
    for (long long i = 0; i <= Max; i++) {
        if (m1-i*pow[pos-1] < 0)
            continue;
        ans += dfs (pos-1, m1-i*pow[pos-1], f2 || (i<Max));
    }
    if (f2)
        dp[pos][m1] = ans;
    return ans;
}

long long f (long long num) {
    l = 0;
    while (num) {
        bit[++l] = num%10;
        num /= 10;
    }
    sum = 0;
    for (int i = 0; a; i++, a/=10) {
        sum += a%10*pow[i];
    } //cout << sum << endl;
    return dfs (l, sum, 0);
}

int main () {
    //freopen ("in.txt", "r", stdin);
    int t, kase = 0;
    pow[0] = 1;
    for (int i = 1; i <= 10; i++) pow[i] = pow[i-1]*2;
    memset (dp, -1, sizeof dp);
    scanf ("%d", &t);
    while (t--) {
        scanf ("%lld%lld", &a, &b);
        printf ("Case #%d: %lld\n", ++kase, f (b));
    }
    return 0;
}


 
 
 

你可能感兴趣的:(HDU 4734 (数位DP))