HDU 4734 F(x) (数位DP)

来源:互联网 发布:蚁群算法基本原理 编辑:程序博客网 时间:2024/04/29 06:02

题意:我们定义十进制数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
原创粉丝点击