您的位置:首页 > 其它

HDU 4734 F(x)

2016-03-16 10:36 274 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3709

[b]数位DP专题:/article/8966394.html

[/b]

题意:一个十进制的数A,定义一个函数f(A) = An * 2^n-1 + An-1 * 2^n-2 + An-2 * 2^n-3 + .... + A1 * 2^0,给出A、B,问有多少数k在[0,B]内,且f(k)<=f(A)。

思路:记忆化搜索+数位dp。用dp[i][j]表示从最高位开始的前i位数中∑f(x)小于等于j的个数。对于不在统计范围的情况,可以用dfs单独计算。一开始num = f(A),从最高位开始枚举,每次确定下来一位,那么num就要减去这个位产生的值,然后一直递归下去。如果有的位正好是B的对应位的上限值,那么我们就不记录答案,因为这种情况因为上界是B可能有些数取不到。



#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <sstream>
#include <queue>
#include <utility>
using namespace std;

#define rep(i,j,k) for (int i=j;i<=k;i++)
#define Rrep(i,j,k) for (int i=j;i>=k;i--)

#define Clean(x,y) memset(x,y,sizeof(x))
#define LL long long
#define ULL unsigned long long
#define inf 0x7fffffff
#define mod %100000007

int dp[10][10000];
int bit[12];
int T;
int A,B;

int dfs(int k,int num,bool flag)
{
if ( num < 0 ) return 0;
if ( k == 0 ) return num>=0;
if ( !flag && dp[k][num]!=-1 ) return dp[k][num];
int ed = ( flag?bit[k]:9 );
int ans = 0;
rep(i,0,ed)
{
ans+=dfs( k - 1 , num - i*(1<<(k-1)) , flag && i == ed );
}
if ( !flag ) dp[k][num] = ans;
return ans;
}

int f(int x)
{
int ans = 0;
int k = 1;
while(x)
{
ans+=( x % 10 ) * k;
k<<=1;
x/=10;
}
return ans;
}

int cal()
{
int len = 0;
while(B)
{
bit[ ++len ] = B % 10;
B/=10;
}
return dfs( len , f(A) , 1 );
}

int main()
{
cin>>T;
Clean(dp,-1);
rep(kase,1,T)
{
scanf("%d %d",&A,&B);
printf("Case #%d: %d\n",kase,cal());
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: