[数位DP] HDU4734 F(x)

HDU4734

题意:设整数x的十进制表示为An*10^n-1 + An-1*10^n-2 ... A1*10^0, 定义函数F(x)=An*2^n-1 + An-1*2^n-2 +...+A1*10^0,然后对任意x∈[0, B]求F(x)值不超过F(A)的x的个数。

解法:数位DP。 DP[i][j]表示1~i位的数中F函数值不超过j的数的个数,DP[len][F(A)]即为答案。

技巧:从F(A)往0搜,如果从0往F(A)搜的话,对不同F(A),DP需要记忆的信息是不同的,每次都重新跑DP会超时。

#include<bits/stdc++.h>
#define ll long long int
using namespace std;
int f(ll x){
    ll res = 0, b = 1;
    while(x){
        res += (x%10)*b;
        x /= 10;
        b *= 2;
    }
    return res;
}
int dp[15][6000], p2[15];
int num[15];
int dfs(int pos, int sum, int f){
    if(sum < 0) return 0;
    if(pos < 1) return sum >= 0;
    if(!f && dp[pos][sum] != -1) return dp[pos][sum];
    int end = f? num[pos] : 9;
    int res = 0;
    for(int i = 0; i <= end; ++i){
        res += dfs(pos-1, sum-i*p2[pos], f && i == end);
    }
    if(!f) dp[pos][sum] = res;
    return res;
}
int solve(int a, int b){
    int len = 0;
    while(b){
        num[++len] = b%10;
        b /= 10;
    }
    return dfs(len, f(a), 1);
}
void init(){
    p2[1] = 1;
    for(int i = 2; i <= 10; ++i) p2[i] = p2[i-1]*2;
    memset(dp, -1, sizeof(dp));
}
int main(){
    init();
    int T, ca = 1;
    scanf("%d", &T);
    while(T--){
        int a, b;
        scanf("%d%d", &a, &b);
        printf("Case #%d: %d\n", ca++, solve(a, b));
    }
}

你可能感兴趣的:(dp,ACM,HDU)