HDU 4734 F(x) 解题报告

题目

题意:

对于十进制数n,各位数是AnAn-1An-2 ... A2A1,定义函数 F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2 * 2 + A1 * 1。求[0,B]中,有多少个数i的F(i)<=F(A)。

题解:

由于指数从10变成了2,所以数变得特别小,999999999也就4599.所以可以预处理,dp[i][j]表示[0,10^i-1]之间的满足F(k)==j的k有多少个。

然后做数位DP,设前面的数和为X,若后面的数可以任意取,则后面取的数的总和不能超过F(A)-X。


//Time:46ms
//Memory:1384KB
//Length:1171B
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
#define MAXN 5000

int dp[12][MAXN],sum[12][MAXN],arr[12];
int dfs(int h,int now)
{
    if(h==-1||now<0)   return now>=0;
    int off=1<<h,ret=0;
    for(int i=0;i<arr[h];++i)
        if(now-i*off>=0)
            ret+=sum[h][now-i*off];
        else    break;
    return ret+dfs(h-1,now-off*arr[h]);
}
int main()
{
    //freopen("/home/moor/Code/input","r",stdin);
    int ncase,a,b;
    scanf("%d",&ncase);
    dp[0][0]=1;
    for(int i=1;i<11;++i)
        for(int j=0;j<MAXN;++j)
            if(dp[i-1][j])
                for(int k=0;k<10;++k)
                    dp[i][j+k*(1<<(i-1))]+=dp[i-1][j];
    for(int i=0;i<11;++i)
    {
        sum[i][0]=dp[i][0];
        for(int j=1;j<MAXN;++j)
            sum[i][j]=sum[i][j-1]+dp[i][j];
    }
    for(int hh=1;hh<=ncase;++hh)
    {
        printf("Case #%d: ",hh);
        scanf("%d%d",&a,&b);
        int tmp=0,off=1,len=0;
        while(a)    tmp+=a%10*off,a/=10,off*=2;
        while(b)    arr[len++]=b%10,b/=10;
        printf("%d\n",dfs(len-1,tmp));
    }
    return 0;
}



你可能感兴趣的:(HDU 4734 F(x) 解题报告)