HUD 4737 数位DP

来源:互联网 发布:mysql优化 编辑:程序博客网 时间:2024/06/07 20:57

题目链接

题意:给出F()函数 求在[0 - B]中有多少个数的F值小于F(A)

方法一:预处理 dp[i][j][st] 表示第i位为j 时 F值不大于st的个数

转移方程 dp[i][j][st] = ∑dp[i - 1][k][st - j * (2^(i -1))]

代码:

#include <cstdio>#include <iostream>#include <queue>#include <cstring>#define sf scanf#define pf printfusing namespace std;typedef long long LL;const int max_st = 9 * (2 << 10) + 50;int dp[15][10][max_st];void init_dp(){    memset(dp,0,sizeof(dp));    for(int i = 0;i < 10;++i) dp[1][i][i] = 1;    for(int i = 0;i < 10;++i){        for(int j = i + 1;j < max_st;++j){            dp[1][i][j] += dp[1][i][j - 1];        }    }    for(int i = 2;i < 11;++i){        for(int j = 0;j < 10;++j){            int temp = j * (1 << (i - 1));            for(int p = temp;p < max_st;++p){                for(int k = 0;k < 10;++k){                    dp[i][j][p] += dp[i - 1][k][p - temp];                }            }        }    }}int digit[15];int solve(int A,int B){    int f_a = 0,temp = 1;    while(A){        f_a = f_a  + (A % 10)*temp;A = A / 10;        temp <<= 1;    }    int len = 0;    while(B){ digit[++len] = B % 10;B = B / 10;}    int pre_sum = 0,ret = 0;    for(int i = len;i;--i){        for(int j = 0;j < digit[i];++j){            ret += dp[i][j][f_a - pre_sum];        }        pre_sum = pre_sum + digit[i] * (1 << (i - 1));        if(pre_sum > f_a) break;    }    return ret;}int main(){    init_dp();    int T,ca = 0,A,B;    sf("%d",&T);    while( T-- ){        sf("%d%d",&A,&B);        pf("Case #%d: %d\n",++ca,solve(A,B + 1));    }    return 0;}

方法二: DFS

代码:

#include <cstdio>#include <iostream>#include <queue>#include <cstring>#define sf scanf#define pf printfusing namespace std;typedef long long LL;const int max_st = 9 * (2 << 10) + 50;int dp[15][max_st];//dp[i][st] 第i位 f值不大于st的个数int digit[15];int f_a;int dfs(int i,int st,bool flag){    if(st < 0) return 0;    if(!i) return dp[i][st] = !flag;    if(!flag && ~dp[i][st]) return dp[i][st];    int ans = 0;    int limit = flag ? digit[i] : 9;    int temp = 1 << (i - 1) ;    for(int j = 0;j <= limit;++j){        ans += dfs(i - 1,st - j * temp,flag && j == limit);    }    if(!flag) dp[i][st] = ans;    return ans;}int solve(int A,int B){    int len = 0,fa_a = 0,temp = 1;    while(B){        digit[++len] = B % 10;B = B / 10;    }    while(A) {fa_a = fa_a + (A % 10) * temp;A = A / 10;temp = temp << 1;}    return dfs(len,fa_a,1);}int main(){    memset(dp,-1,sizeof(dp));    int T,ca = 0;sf("%d",&T);    int A,B;    while( T-- ){        sf("%d%d",&A,&B);        pf("Case #%d: %d\n",++ca,solve(A,B + 1));    }    return 0;}
0 0