HDU 4734 F(x) 数位DP

数位DP 越来越顺了。但是无脑了一下,对于每组数据都删除记忆,10000组数据档当然TLE了。

 

题意:求0~b中有多少个数X, 其f(x)<=f(a)

 

 

分析:

设g[i][j]表示长度为i的数,距离f(a)还剩j的量。

g[i][j]=Σ(g[i-1][j-k*2^(i-1)]  (0<=k<=9)

 

然后就是套路了。

#include <stdio.h>
#include <string.h>
int g[20][10000];
int f(int x)
{
    int sum=0;
    int y=1;
    while (x>0)
    {
        sum+=y*(x%10);
        x/=10;
        y=y*2;
    }
    return sum;
}
int dp(int i,int j)
{
    if (j<0)
    {
        return 0;
    }
    if (g[i][j]!=-1)
    {
        return g[i][j];
    }
    if (i==0)
    {
        if (j<0)
        {
            return 0;
        }
        else
        {
            return g[i][j]=1;
        }
    }
    int ans=0;
    for (int k=0;k<=9;k++)
    {
        if ((j-k*(1<<(i-1)))>=0)
            ans+=dp(i-1,j-k*(1<<(i-1)));
    }
    return g[i][j]=ans;
}
int main()
{
    int i,j,k;
    int t;
    int len;
    int a,b;
    int last;
    int digit[100];
    int cas=0;
    scanf("%d",&t);
    memset(g,-1,sizeof(g));
    while (t--)
    {

        scanf("%d%d",&a,&b);
        last=f(a);
        len=0;
        b++;
        while (b>0)
        {
            digit[++len]=b%10;
            b/=10;
        }
        int ans=0;
        for (i=len;i>=1;i--)
        {
            for (j=0;j<digit[i];j++)
            {
                ans+=dp(i-1,last-j*(1<<(i-1)));
            }
            last-=digit[i]*(1<<(i-1));
        }
        printf("Case #%d: %d\n",++cas,ans);
    }
    return 0;
}

这里有个浓缩版。 from  CXL。

#include <cstdio>
#include <cstring>

int dp[12][10000];
int num[30];

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

int dfs(int i, int f, bool isQuery) {
    if (f < 0) return 0;
    int &nowdp = dp[i][f];
    if (!isQuery && ~nowdp) return nowdp;
    if (i == 0) {
        return 1;
    }
    int end = isQuery?num[i]:9; /*这里不一样哦!*/
    int ans = 0;
    for (int j = 0; j <= end; j++) {
        int nextf = f-j*(1<<(i-1)); /*这里不一样哦!*/
        ans += dfs(i-1, nextf, isQuery && j==end);
    }
    if (!isQuery) nowdp = ans;
    return ans;
}

int cal(int a, int x) {
    int len = 0;
    if (x == 0) {
        num[++len] = 0;
    } else {
        while (x) {
            num[++len] = x%10;
            x/=10;
        }
    }
    return dfs(len, getf(a), true); /*这里不一样哦!*/
}

int main() {
    int t;
    scanf("%d", &t);
    memset(dp, -1, sizeof(dp));
    int cas = 1;
    while (t--) {
        printf("Case #%d: ", cas++);
        int a, b;
        scanf("%d%d", &a, &b);
        printf("%d\n", cal(a,b));
    }
    return 0;
}

 

posted on 2014-03-14 17:29  six_god  阅读(243)  评论(0编辑  收藏  举报

导航