//hdu 4734 F(x) 数位dp的题
//
//我们定义十进制数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[i][j]表示i位值<=j 的总数
//bit位由低位到高位存储
//dfs由高位到低位进行
//注意dp数组初始化那里,t了我那么多发
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<string>
using namespace std;
int len;
int cas,A,B;
int dp[20][200000];
int bit[20];
int dfs(int pos,int num,bool flag)
{
if(pos==-1) return num>=0;///关于0的处理在这里
if(num<0) return 0;
if(!flag&&dp[pos][num]!=-1) return dp[pos][num];///记忆化搜索。。减少时间什么的
int endd=flag?bit[pos]:9;
int ans=0;
for(int i=0;i<=endd;i++)
{
ans+=dfs(pos-1,num-i*(1<<pos),flag&&(i==endd));//如果到了结尾就要用bit[pos]不能用9
///一开始卡在这里,<<是左移运算符,不是乘二运算符,要加1<<pos!!!
}
if(!flag)
dp[pos][num]=ans;//不到最后一位,不能统计这一位的dp值
return ans;
}
int f(int x)
{
int ret=0,num=0;
while(x)
{
ret+=(x%10)*(1<<num);
x/=10;
num++;
}
return ret;
}
int main()
{
//freopen("in.txt","r",stdin);
scanf("%d",&cas);
memset(dp,-1,sizeof(dp));///最大的优化在于dp数组初始化在外面,因为跑的是一样的。下面的可以接着用
for(int ca=1;ca<=cas;ca++)
{
scanf("%d%d",&A,&B);
int len=0;
while(B)
{
bit[len++]=B%10;
B/=10;
}
printf("Case #%d: %d\n",ca,dfs(len-1,f(A),true));
}
}
hdu 4734 数位DP
最新推荐文章于 2021-01-19 21:31:29 发布