ural 1057 Amount of Degrees

题目地址:http://vjudge.net/problem/viewProblem.action?id=18851 (hust)

题意:给出一个区间[x,y],在区间里找出这样的数:一个数可以表示成k个不同的b进制的次方之和,求这种数的个数。

例子讲解:x=15,y=20,k=2,b=2;那么区间里第一个满足条件的数就是17,因为17=2^4+2^0,为什么不是16,因为16=2^3+2^3,两个数相同了,所以不是16而是17。另外还有两个就是18,20;(18=2^4+2^1;20=2^4+2^2.)所以[x,y]满足条件的数的个数就是3个。

解法:数位DP。集训队论文《浅谈数位类统计问题》--刘聪  中有详细讲解,不过,对于我来说,DP思维还不够,学习数位DP还是根据别人博客的记忆化搜索方法来理解入门的,我比较偏向于这种方法。大牛们请谅解我这一菜鸟,我也搞不清楚数位DP的两种实现方式:记忆化搜索和递推的优势和弊端以及时间效率上的区别。

 1 #include<iostream>

 2 #include<cstdio>

 3 #include<cstring>

 4 #include<cmath>

 5 #include<cstdlib>

 6 #include<algorithm>

 7 #define inf 0x7fffffff

 8 #define exp 1e-10

 9 #define PI 3.141592654

10 using namespace std;

11 typedef long long LL;

12 LL digit[40];

13 LL dp[40][25][2];

14 LL x,y,k,b;

15 LL dfs(LL len,LL num,bool flag,bool fp)

16 {

17     if (!len)

18     {

19         if (num==k) return 1;

20         return 0;

21     }

22     if (!fp && dp[len][num][flag]!=-1) return dp[len][num][flag];

23     LL ret=0;

24     LL fpmax= fp ? min((LL)1,digit[len]) : 1;

25     for (LL i=0 ;i<=fpmax ;i++)

26     {

27         if (i==0) ret += dfs(len-1,num,flag && !i,fp && i==digit[len]);

28         else ret += dfs(len-1,num+1,false,fp && i==digit[len]);

29     }

30     if (!fp) return dp[len][num][flag]=ret;

31     return ret;

32 }

33 LL f(LL n)

34 {

35     LL len=0;

36     while (n)

37     {

38         digit[++len]=n%b;

39         n /= b;

40     }

41     return dfs(len,0,true,true);

42 }

43 int main()

44 {

45     while (scanf("%I64d%I64d%I64d%I64d",&x,&y,&k,&b)!=EOF)

46     {

47         memset(dp,-1,sizeof(dp));

48         if (y<x) swap(x,y);

49         printf("%I64d\n",f(y)-f(x-1));

50     }

51     return 0;

52 }

 

 

你可能感兴趣的:(mount)