HDU4734 F(x) 数位dp

网址:https://vjudge.net/problem/HDU-4734

题意:

定义函数$f(x)$,给出$a,b$,求范围$0$至$b$中有多少数不大于$f(a)$。

题解:

数位dp板子题,记录状态的时候就用$f(a)$和$sum$比较,$sum$过大了直接返回$0$,其他的正常记录即可,本题时限少,如果每一次都$memset$会TLE,由于数位$dp$的$dp$数组的内容和输入无关(本题数位的模不变,若数位的模改变就需要重新$memset$),保存的状态可以一直使用,所以只需$memset$一次。这样子就可以AC。

AC代码:

#include <bits/stdc++.h>
using namespace std;
int dp[10][5000],a[10];
int all;
int dfs(int pos,int sum,bool lim)
{
    if(pos==-1)
        return sum<=all;
    if(all<sum)
        return 0;
    if(!lim&&dp[pos][all-sum]!=-1)
        return dp[pos][all-sum];
    int ans=0;
    int res=lim?a[pos]:9;
    for(int i=0;i<=res;++i)
        ans+=dfs(pos-1,sum+i*(1<<pos),lim&&i==a[pos]);
    if(!lim)
        dp[pos][all-sum]=ans;
    return ans;
}
int f(int x)
{
    int ans=0,pos=1;
    while(x)
    {
        ans+=(x%10)*pos;
        pos<<=1;
        x/=10;
    }
    return ans;
}
int solve(int x)
{
    int pos=0;
    while(x)
    {
        a[pos++]=x%10;
        x/=10;
    }
    return dfs(pos-1,0,true);
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int n,a,b;
    cin>>n;
    memset(dp,-1,sizeof(dp));//状态可以一直使用,除非数位进制变化
    for(int i=1;i<=n;++i)
    {
        cin>>a>>b;
        all=f(a);
        cout<<"Case #"<<i<<": "<<solve(b)<<endl;
    }
    return 0;
}

 

posted @ 2019-07-21 00:01  Aya_Uchida  阅读(116)  评论(0编辑  收藏  举报