http://acm.hdu.edu.cn/showproblem.php?pid=4734
题目描述:
0~B里面,F(b)<=F(A)的有多少个。
F(x)=A n * 2 n-1 + A n-1 * 2 n-2 + ... + A 2 * 2 + A 1 * 1. 每位的数*对应2的n次方的和。
分析:
数位dp。dp[pos] [r] 表示在第pos位数,r为该最大数F(A)- 满足的和。
先求最大的F(A),每推到一位,用F(A)-这一位数对应题意的积,得到的就是r。
memset(dp,-1,sizeof dp)要放在括号前面,不然会T。
代码:
#include<vector> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> using namespace std; typedef long long ll; const int maxn=1e4; int F;//上界 int dp[15][maxn]; int a[20]; int pow2[20]; int dfs(int pos,int r,bool limit) { if(pos==-1) return r>=0; if(r<0) return 0; if(!limit&&dp[pos][r]!=-1) return dp[pos][r]; int up=limit?a[pos]:9; int ans=0; for(int i=0;i<=up;i++) { if(r<i*pow2[pos]) break; ans+=dfs(pos-1,r-i*pow2[pos],limit&&i==a[pos]); } if(!limit) dp[pos][r]=ans; return ans; } int solve(int x) { int pos=0; while(x) { a[pos++]=x%10; x/=10; } return dfs(pos-1,F,1); } int main() { pow2[0]=1; for(int i=1;i<=15;i++) { pow2[i]=pow2[i-1]*2; } int T;scanf("%d",&T); memset(dp,-1,sizeof dp); for(int i=1;i<=T;i++) { int A,B; scanf("%d%d",&A,&B); F=0; int k=0; while(A) { F+=(A%10)*pow2[k]; A/=10,k++; } printf("Case #%d: %d\n",i,solve(B)); } return 0; }