您的位置:首页 > 其它

hdu-4734-数位Dp

2016-08-05 16:31 267 查看
按照题意推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个状态是因为往后转移的时候会遇到很多重复的情况。
//可根据需要增加维数,例如pre
int  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);

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: