您的位置:首页 > 其它

hdu 4734 F(x)(数位dp)

2017-08-30 22:07 316 查看
一个十进制数字x,有n位数字,表示为AnAn-1….A1,定义F(x)=An∗2n−1+An−1∗2n−2+...+A2∗2+A1∗1

现在给你A和B,计算在[0,B]之间有多少数字的F(num) <= F(A)

参考:http://blog.csdn.net/wust_zzwh/article/details/52100392

建议看看这个链接,里面讲的挺详细

先分析状态,F(x)就是计算每位的权值,dp[pos][sum]就是表示i位(包含前导0,即000023)的数字,这些数字的和<=sum的数字一共多少。由于A是题目给出的,所以每次询问的F(A)就是变化的,F(A)最大在4600左右,要想使得记忆化数组在每次询问的时候都能使用,则需要添加一个状态来标记不同的F(A),则记忆化数组为dp[10][4600][4600],数组太大,开不下,而且状态这么多,肯定超时。这时候就要换个思路了,dp[pos][sum]中的sum不再表示当前枚举过的数字的权值和,而是表示枚举到pos位置后,还需要sum的权值才能到达F(A),这样sum这个状态就和F(A)没关系了。

#include <stdio.h>
#include <string.h>

const int MAXN = 5e4+10;
int dp[12][MAXN];
int digit[12];
int len,all;

int f(int num)
{
int ret = 0,cnt = 0;
while(num)
{
ret += (num%10)*(1<<cnt);
num /= 10;
++cnt;
}
return ret;
}

void calc(int num)
{
len = 0;
while(num)
{
digit[len++] = num%10;
num /= 10;
}
}

int dfs(int i, int s, bool e)
{
if(i == -1) return s <= all;
if(s > all) return 0;
if(!e && ~dp[i][all-s]) return dp[i][all-s];
int res = 0;
int u = e?digit[i]:9;
for(int d = 0; d <= u; ++d)
res += dfs(i-1,s+d*(1<<i),e&&d==u);
return e?res:dp[i][all-s]=res;
}

int solve(int num)
{
calc(num);
return dfs(len-1, 0, true);
}

int main()
{
int T,a,b,time = 1;
memset(dp,-1,sizeof(dp));
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&a,&b);
all = f(a);
printf("Case #%d: %d\n",time++,solve(b));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: