题意:对于一个n位的数x(An,An-1,An-2,An-3...A2A1),定义F(x)=An*2^n-1+An-1*2n-2+..+A1*1。给定两个数A,B,求满足k∈[0,B]且F[k]<=F[A]的数的个数。
比较好写的数位DP。首先一组数据中的每个测试用例的A值不同,为了防止每次都要重新清空dp数组,我们把status值设成F[A]-F[k],每次递归保证status的非负性即可。
#include<iostream> #include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #define FOR(i,x,y) for(int i=(x);i<=(y);i++) #define DOR(i,x,y) for(int i=(x);i>=(y);i--) using namespace std; int dp[13][5003]; int num[13]; int F(int x) { int f=1,res=0; while(x) { res+=f*(x%10); f<<=1; x/=10; } return res; } int dfs(int k,int status,bool ismax) { if(k==0)return 1; if(!ismax && ~dp[k][status])return dp[k][status]; int maxer=ismax?num[k]:9,res=0; FOR(i,0,maxer) if(status>=i*(1<<k-1)) res+=dfs(k-1,status-i*(1<<k-1),ismax&&i==maxer); if(!ismax)dp[k][status]=res; return res; } int solve(int A,int B) { int p=0; while(B) { num[++p]=B%10; B/=10; } return dfs(p,A,1); } int main() { int T; scanf("%d",&T); memset(dp,-1,sizeof(dp)); FOR(Ti,1,T) { int A,B; scanf("%d%d",&A,&B); printf("Case #%d: %d\n",Ti,solve(F(A),B)); } return 0; }