HDU 4734 F(x) (数位DP)

题意:我们定义十进制数x的权值为f(x) = a(n)*2^(n-1)+a(n-1)*2(n-2)+...a(2)*2+a(1)*1,a(i)表示十进制数x中第i位的数字。题目给出a,b,求出[0,b]有多少个不大于f(a)的数。

我理解的数位DP就是通过按位记忆化搜索找出所有满足条件的小于等于n的数。然后对于第i位,状态s是由其高位确定的。

数位DP的题目一般都很明显,关键在于状态的设计。看了一天的论文和模版,现在开窍了。

对于数位DP,状态通常比较容易写出,但是写出的状态可能有很多不合适,比如说爆数组。。。

那么要对状态进行压缩,或者重新确定状态(重新确定状态其实就是换一种方式搜索,要想好怎样更好的搜索)。

思路:开始设的dp[i][s][k] ,s为i的高位与2的幂的和且最后结果<=k 的数字个数。

显然是爆数组的。那么我设dp[i][s],s为目标-i的高位与2的幂,且最后结果>=0 的数字的个数。


我的代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>

using namespace std;

int a,b,dp[12][20000],pow2[12];
int bit[12],top,target;

void init(){
    memset(dp,-1,sizeof(dp));
    pow2[0] = 1;
    for(int i=1;i<12;i++) pow2[i] = 2*pow2[i-1];
    //for(int i=0;i<12;i++) cout<<pow2[i]<<" ";cout<<endl;
}

void func(int n){
    top = 0;target = 0;
    for(;n;n/=10) bit[top++] = n%10;
    for(int i=0;i<top;i++) target += bit[i]*pow2[i];
}

int dfs(int i,int s,bool e){
    if(s < 0) return 0;
    if(i == -1) return s >= 0 ? 1 : 0;
    if(!e && dp[i][s] != -1) return dp[i][s];
    int res = 0;
    int d,u = e ? bit[i] : 9;
    for(d = 0 ; d <= u ; d++){
        res += dfs(i-1,s-pow2[i]*d,e&&(d==u));
    }
    return e ? res : dp[i][s] = res;
}

int solve(int n){
    top = 0;
    for(;n;n/=10) bit[top++] = n%10;
    return dfs(top-1,target,1);
}

int main(){
    init();
    int cas;
    scanf("%d",&cas);
    for(int T=1;T<=cas;T++){
        scanf("%d%d",&a,&b);func(a);
        printf("Case #%d: %d\n",T,solve(b));
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值