hdu-4734-数位Dp

来源:互联网 发布:广州房地产交易数据 编辑:程序博客网 时间:2024/05/29 11:59

按照题意推dp就好

从最高位开始,根据是否受限往下递推记忆化保存结果


#include <cstdio>#include <cmath>#include <cstring>#include <string>#include <algorithm>#include <queue>#include <map>#include <set>#include <vector>#include <iostream>using namespace std;typedef int  ll;const int maxn=5005+500;int ans=0;int dp[11][maxn];int aa[11];//    pos    = 当前处理的位置(一般从高位到低位)  //    sum =限制不超过 F(a) //    limit  = 是否受限,也即当前处理这位能否随便取值。如567,当前处理6这位, //            如果前面取的是4,则当前这位可以取0-9。如果前面取的5,那么当前 //            这位就不能随便取,不然会超出这个数的范围,所以如果前面取5的 //            话此时的limit=1,也就是说当前只可以取0-6。 //int F(int b){      int len=0;    while(b)    {        aa[++len]=b%10;        b/=10;    }    int sum=0;    for (int i=len; i>=1; i--)    {        sum+=(1<<(i-1))*aa[i];    }    return sum;}//    用DP数组保存这2个状态是因为往后转移的时候会遇到很多重复的情况。//可根据需要增加维数,例如preint  dfs(int pos,int sum,int flag){    int ans=0;    if (pos==0)    //已结搜到尽头,返回"是否找到了答案"这个状态。    {        if (sum>=0) return 1;        else return 0;    }    if (sum<0) return  0;  //DP里保存的是完整的,也即不受限的答案,所以如果满足的话,可以直接返回。    if (!flag &&dp[pos][sum]!=-1) return dp[pos][sum];    int up;    if (flag) up=aa[pos];    else up=9;//根据是否受限确定枚举的上界    for (int i=0; i<=up; i++)    {        int ff;        if (!flag) ff=0;        else        {            if (i==up) ff=1;            else ff=0;        }        ans +=dfs(pos-1,sum-i*(1<<(pos-1)),ff);    }    //DP里保存完整的、取到尽头的数据    if (!flag)        dp[pos][sum]=ans;    return ans;}int main(){    memset(dp,-1,sizeof dp);    int tt,cas=0;    scanf("%d",&tt);    int m;    int cnt=1;    while (tt--)    {        int a,b;        scanf("%d%d",&a,&b);        int sum =F(a);        int len=0;        while(b)        {            aa[++len]=b%10;            b/=10;        }        ans=dfs(len,sum,1);        printf("Case #%d: %d\n",cnt++,ans);    }}


0 0
原创粉丝点击