HDU 4734 F(x) DP, 数位DP

时间:2022-12-16 10:41:25

  题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4734

  题目描述: 给出两个数A, B, 求出小于B且F(i)小于F(A)的所有i的个数

  解题思路: 典型的数位DP, dfs(int len, int cur, int limit) 表示处理到第len位, F(A)还剩cur, 是否限制的答案

  代码: 

HDU 4734 F(x) DP, 数位DPHDU 4734 F(x) DP, 数位DP
#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <map>
#include <cstring>
#include <iterator>
#include <cmath>
#include <algorithm>
#include <stack>
#include <deque>
#include <map>

#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
typedef long long LL;
using namespace std;
//const int maxn = 70000+10;
int digit[20];
int dp[20][200000]; // digit处理到第i位a还剩n的解决方案

int dfs(int len, int cur, int limit) {
    if( len == -1 ) return cur >= 0; // 所有都判定完了, 如果cur还>=0就证明还有一种方案
    if( cur < 0 ) return 0;
    if( !limit && dp[len][cur] != -1 ) return dp[len][cur];
    int ret = 0;
    int templimit = limit ? digit[len] : 9;
    for( int i = 0; i <= templimit; i++ ) {;
        ret += dfs( len-1, cur-i*(1<<len), limit && i == templimit );
    }
    if( !limit ) dp[len][cur] = ret;
    return ret;
}

int F(int A) {
    int ret = 0;
    int len = 0;
    while( A ) {
        ret += (A % 10) * (1 << len);
        len++;
        A /= 10;
    }
    return ret;
}

int fun(int A, int n) {
    int cnt = 0;
    while( n ) {
        digit[cnt++] = n % 10;
        n /= 10;
    }
    
    return dfs( cnt-1, A, 1 );
}

int main() {
    int t;
    while( scanf( "%d", &t) == 1 ) {
        int cases = 0;
        memset(dp, -1, sizeof(dp));
        while( t-- ) {
            int A, n;
            scanf( "%d%d", &A, &n );
            int ans = fun(F(A), n);
            printf( "Case #%d: %d\n", ++cases, ans );
        }
    }
    return 0;
}
View Code

  思考: 倒是没有多大问题, 就是老TLE, 后来把数组改成dp[20][20000]就过了, 不知道为什么, 很迷, 照理来说y应该开到两千就过了的啊