HDU4734 F(x) (数位DP)

(如此简短的题目给人一种莫名的压迫感......)

题目中定义一个数的权值求解函数:F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2 * 2 + A1 * 1. 观察可知:权值的表达式与数的位数相关,再加上要分离每个位上的数字,那么就不难想到数位DP了。

dp[pos][j]表示pos位下小等于j的元素个数,代码如下:

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 const int N=50000;
 5 int dig[25],a,b;
 6 int dp[11][N];
 7 
 8 int dfs(int pos,int fa,bool limit){
 9     if(pos==0) return fa>=0;
10     if(fa<0) return 0;//剪枝
11     if(!limit&&dp[pos][fa]!=-1) return dp[pos][fa];
12     int len=limit?dig[pos]:9;
13     int ans=0;
14     for(int i=0;i<=len;i++)
15         ans+=dfs(pos-1,fa-i*(1<<(pos-1)),limit&&i==len);
16     if(!limit) dp[pos][fa]=ans;
17     return ans;
18 }
19 
20 int f(int n){//f函数 
21     int ans=0,len=1;
22     while(n){
23         ans+=n%10*len;
24         len*=2;
25         n/=10;
26     }
27     return ans;
28 }
29 
30 int solve(int x){
31     int pos=0;
32     while(x){
33         dig[++pos]=x%10;
34         x/=10;
35     }
36     return dfs(pos,f(a),1);
37 }
38 
39 int main(){
40     int T,cas=1;
41     scanf("%d",&T);
42     memset(dp,-1,sizeof(dp));
43     while(T--){
44         scanf("%d%d",&a,&b);
45         printf("Case #%d: %d\n",cas++,solve(b));
46     }
47     return 0;
48 }

第10行的剪枝含义:当前的fa已经小于0,说明已经不满足题意了,就没有再递归下去的必要了。

posted @ 2022-06-24 21:50  YHXo  阅读(15)  评论(0编辑  收藏  举报