hdu 4734 F(x)(数位dp)

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4734
题意:就是给一个函数 f ( x ) 原来的十进制变成二进制,但是系数不变,最后得到的十进制数

数位 d p 是上次寒假集训学的,没怎么学会。。。现在才来补
这道题的记录的状态有点特别,是记录枚举到这一位的和与 f ( A ) 的差值,大于 f ( A ) 的直接就不要了
按照哪位大佬的说法,我们正常来写的话,就应该是记录现在的 s u m ,以及每次的 f ( A ) ,然后来比较进行取舍,但是每个 p o s s u m 不同吧,而且每次询问的 f ( A ) 也不同,哇~那就要把这两种状态都记录下来,内存根本装不下,然后就想到记录两个的差值,真是太 T M 的机智了~

#include"bits/stdc++.h"
#define out(x) cout<<#x<<"="<<x
#define C(n,m) ((long long)fac[(n)]*inv[(m)]%MOD*inv[(n)-(m)]%MOD)
using namespace std;
typedef long long LL;
const int maxn=1e5+5;
const int MOD=1e9+7;
int tot,a[20];
map<int,int>dp[20];
LL f(LL x)
{
    if(x==0)return 0;
    LL ans=f(x/10);
    return (ans<<1)+x%10;
}
LL dfs(int pos,int sum,bool lim)
{
    if(sum>tot)return 0;                //大于f(A)的直接就不要了 
    if(pos==-1)return 1;
    if(lim==0&&dp[pos][tot-sum])return dp[pos][tot-sum];
    int up=lim?a[pos]:9;
    LL cnt=0;
    for(int i=0;i<=up;i++)
    {
        cnt+=dfs(pos-1,sum+i*(1<<pos),lim&&i==up);
    }
    if(lim==0)dp[pos][tot-sum]=cnt;     //以差值作为记录的状态 
    return cnt;
}
LL solve(LL n)
{
    int pos=-1;
    while(n)
    {
        a[++pos]=n%10;
        n/=10;
    }
    return dfs(pos,0,true);
}
int main()
{
    int T;
    cin>>T;
    for(int Case=1;Case<=T;Case++)
    {
        int A,B;
        cin>>A>>B;
        tot=f(A);
        cout<<"Case #"<<Case<<": "<<solve(B)<<endl;
    }
}

猜你喜欢

转载自blog.csdn.net/SwustLpf/article/details/81449518