题意:给了一个函数f(a),要求从0到b之间有多少个数字x,满足f(x)<= f(a)。
思路:数位DP。
开始的时候把每一组数据都进行了一遍预处理,导致了超时。后来看了别人的代码发现只用预处理一遍就好了。
代码如下:
第一种实现方法:自底向上的DP
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<map>
#include<set>
#include<list>
#include<stack>
#include<algorithm>
#include<queue>
#include<vector>
#include<time.h>
#include<iomanip>
#include<assert.h>
using namespace std;
int pre[12][5000];
int f(int a)
{
int ret = 0;
int tot = 0;
while(a){
ret += (a%10)*(1<<tot);
a/=10;
tot++;
}
return ret;
}
int digit[15];
int tot;
int dfs(int b,int fa,int p)
{
if(fa < 0)return 0;
if(p<0)return 0;
int ret = 0;
for(int i = 0 ;i < digit[p]; ++i){
if(fa - i*(1<<p)<0)break;
if(p>0)
ret += pre[p-1][fa - i*(1<<p)];
else ret++;
}
ret += dfs(b,fa-digit[p]*(1<<p),p-1);
return ret;
}
int main()
{
// freopen("data.txt","r",stdin);
int T;
scanf("%d",&T);
int kase = 0;
memset(pre,0,sizeof(pre));
for(int i = 0; i<= 4999;++i){
pre[0][i] = min(i+1,10);
}
for(int i = 1 ;i < 11 ;++i){
pre[i][0] = 1;
for(int j = 1; j <=4999; ++j){
for(int k = 0 ; k < 10; ++k){
int s = k*(1<<i);
if(s<=j )
pre[i][j] += pre[i-1][j-s];
else break;
}
}
}
while(T--){
printf("Case #%d: ",++kase);
int a,b;
scanf("%d%d",&a,&b);
int fa = f(a);
tot = 0;
int tmp = b+1;
while(tmp){
digit[tot++] = tmp %10;
tmp /=10;
}
int ans = dfs(b,fa,tot-1);
printf("%d\n",ans);
}
return 0;
}
第二种实现方法:自顶向下的DP
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<map>
#include<set>
#include<list>
#include<stack>
#include<algorithm>
#include<queue>
#include<vector>
#include<time.h>
#include<iomanip>
#include<assert.h>
using namespace std;
int dp[12][5000];
int f(int a)
{
int ret = 0;
int tot = 0;
while(a){
ret += (a%10)*(1<<tot);
a/=10;
tot++;
}
return ret;
}
int digit[15];
int tot;
int dfs(int fa,int p,bool flag)
{
if(flag && dp[p][fa]>=0){
return dp[p][fa];
}
if(p < 0 )return 0;
if(fa < 0)return 0;
if(fa == 0)return 1;
int top = flag? 9 : digit[p];
int ret = 0;
for(int i = 0 ; i <= top ; ++i){
int s = i*(1<<p);
if(fa - s<0)break;
if(p>0)
ret += dfs(fa-s,p-1,flag || i<top);
else ret++;
}
if(flag) dp[p][fa] = ret;
return ret;
}
int main()
{
// freopen("data.txt","r",stdin);
int T;
scanf("%d",&T);
int kase = 0;
memset(dp,-1,sizeof(dp));
while(T--){
printf("Case #%d: ",++kase);
int a,b;
scanf("%d%d",&a,&b);
int fa = f(a);
tot = 0;
int tmp = b;
while(tmp){
digit[tot++] = tmp%10;
tmp /=10;
}
printf("%d\n",dfs(fa,tot-1,0));
}
return 0;
}