码迷,mamicode.com
首页 > 其他好文 > 详细

URAL 1057 Amount of Degrees (数位DP,入门)

时间:2015-10-02 00:09:51      阅读:220      评论:0      收藏:0      [点我收藏+]

标签:

 

 

 

题意:

  求给定区间[X,Y]中满足下列条件的整数个数:这个数恰好等于K个互不相等的,B的整数次幂之和。例如,设X=15,Y=20,K=2,B=2,则有且仅有下列三个数满足了要求:  17 = 24+20, 18 = 24+21, 20 = 24+22。(以B为底数,幂次数不允许相同)

  参考论文--》》论文中的题。

 

 

思路:

  论文倒是容易看明白,但是这个转成B进制的思想一直转不过来。其实转成B进制后变成 a1*Bn+a2*Bn-1...an*B0。其中ai是系数。范围是[0,B-1]。但是看了论文知道,里面画的那棵01树(树上的01就是代表系数a),只有从根走到叶子,经过的1的个数为K才是满足要求的。那么如果a大于0怎么办?那么从树上该点开始的整棵子树就可以全部进行考虑了。而如果刚好考虑的位为1的呢?那么取该位为0的那棵子树就行了。

 

 

 

  两种实现

 

技术分享
 1 //#include <bits/stdc++.h>
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <cmath>
 6 #include <map>
 7 #include <algorithm>
 8 #include <vector>
 9 #include <iostream>
10 #define pii pair<int,int>
11 #define INF 0x7f3f3f3f
12 #define LL long long
13 using namespace std;
14 const double PI  = acos(-1.0);
15 const int N=35; //注意大小
16 
17 int f[N][N];
18 
19 void pre_cal()  //预处理组合数
20 {
21     f[0][0]=1;
22     for(int i=1; i<N; i++) //位数
23     {
24         f[i][0]=f[i][i]=1;
25         for(int j=1; j<i; j++) //多少个1
26         {
27             f[i][j]=f[i-1][j]+f[i-1][j-1];
28         }
29     }
30 }
31 /*
32 void pre_cal()
33 {
34     f[0][0] = 1;
35     for (int i = 1; i <= 32; i++)
36     {
37         f[i][0] = f[i - 1][0];
38         for (int j = 1; j <= i; j++)
39             f[i][j] = f[i - 1][j] + f[i - 1][j - 1];
40     }
41 }*/
42 int bit[N];
43 int cal(int n,int k,int b)
44 {
45     memset(bit, 0, sizeof(bit));
46     int len=0, cnt=0, ans=0;
47     while(n)    //转成b进制
48     {
49         bit[++len]=n%b;
50         n/=b;
51     }
52     for(int i=len; i>0; i--)
53     {
54         if(bit[i]>1)
55         {
56             ans+=f[i][k-cnt];   //取整棵子树
57             break;
58         }
59         else if( bit[i]==1 )
60         {
61             ans+=f[i-1][k-cnt]; //统计左边的
62             if(++cnt>k)   break;  //已超
63         }
64     }
65     if(cnt==k)  ans++;
66     return ans;
67 }
68 
69 int main()
70 {
71     //freopen("input.txt","r",stdin);
72     pre_cal();
73     int x, y, k, b;
74     while(~scanf("%d%d%d%d",&x,&y,&k,&b))
75         printf("%d\n", cal(y,k,b)-cal(x-1,k,b));
76     return 0;
77 }
AC代码

 

技术分享
 1 //#include <bits/stdc++.h>
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <cmath>
 6 #include <map>
 7 #include <algorithm>
 8 #include <vector>
 9 #include <iostream>
10 #define pii pair<int,int>
11 #define INF 0x7f3f3f3f
12 #define LL long long
13 using namespace std;
14 const double PI  = acos(-1.0);
15 const int N=35;
16 
17 int f[N][N];
18 void pre_cal()  //预处理组合数
19 {
20     f[0][0]=1;
21     for(int i=1; i<N; i++) //位数
22     {
23         f[i][0]=f[i][i]=1;
24         for(int j=1; j<i; j++) //多少个1
25         {
26             f[i][j]=f[i-1][j]+f[i-1][j-1];
27         }
28     }
29 }
30 int bit[N];
31 int cal(int n,int k,int b)
32 {
33     memset(bit, 0, sizeof(bit));
34     int len=0, cnt=0, ans=0, flag=1;
35     while(n)    //转成b进制
36     {
37         bit[++len]=n%b;
38         n/=b;
39         if(bit[len]>1)  flag=0;
40     }
41 
42     if(flag==0)
43     {
44         //找到第一位大于1的,改为1,然后后面可以全部改成1了
45         for(int i=len; i>0; i--)
46             if(bit[i]>1)
47             {
48                 for(int j=i; j>0; j--)    bit[j]=1;
49                 break;
50             }
51     }
52 
53     for(int i=len; i>0; i--)
54     {
55         if( bit[i] )
56         {
57             ans+=f[i-1][k-cnt]; //统计左边的
58             if(++cnt>k)   break;  //已超
59         }
60     }
61     if(cnt==k) ans++;
62     return ans;
63 }
64 
65 int main()
66 {
67     //freopen("input.txt","r",stdin);
68     pre_cal();
69     int x, y, k, b;
70     while(~scanf("%d%d%d%d",&x,&y,&k,&b))
71         printf("%d\n", cal(y,k,b)-cal(x-1,k,b));
72     return 0;
73 }
AC代码

 

URAL 1057 Amount of Degrees (数位DP,入门)

标签:

原文地址:http://www.cnblogs.com/xcw0754/p/4851713.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!