题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1057
1057. Amount of Degrees
Memory limit: 64 MB
18 = 24+21,
20 = 24+22.
Input
Output
Sample
input | output |
---|---|
15 20
2
2
|
3
|
具体看代码,代码中有对各部分的详细解释
<span style="font-size:18px;">#include<cstdio>
#include<iostream>
using namespace std;
int f[35][35];///高度为i时,有j个1的个数
int changetwo(int x,int b)
{
int num[35]={0};
int ans=0;
int i=0;
while(x>0)///转换成b进制下的数
{
num[++i]=x%b;
x/=b;
}
int temp=i;///记录转换之后的数的长度
while(num[i]<=1)///找到第一个大于等于2的数
{
i--;
}
while(i>=1)///从上面找到的位置开始把后面都变成1
{
num[i]=1;
i--;
}
while(temp>=1)///把存在数组里的数组合成一个二进制数
{
ans=ans*2+num[temp];
temp--;
}
return ans;
}
///预处理
void init()
{
f[0][0]=1;
for(int i=1;i<=31;i++)
{
f[i][0]=f[i-1][0];
for(int j=1;j<=i;j++)
{
f[i][j]=f[i-1][j]+f[i-1][j-1];///当前高度为i时要求j个1为加上左右子树的j个1个数
}
}
}
int calc(int x,int k)
{
int tot=0,ans=0;///分别表示当前已经统计出几个1,符合条件的个数
for(int i=31;i>0;i--)///从根节点出发向叶子节点查找
{
if(x&(1<<i))///找当前节点有没有1
{
tot++;
if(tot>k)
break;
x=x^(1<<i);///找到之后把1去掉
}
if((1<<(i-1))<=x)
ans+=f[i-1][k-tot];///如果x的下一位是1的话,那么从下一个界定啊开始它的做字数全都需要统计
}
if(tot+x==k) ans++;
return ans;
}
int main()
{
int x,y;
int k,b;
scanf("%d%d%d%d",&x,&y,&k,&b);
init();
if(b==2)
printf("%d\n",calc(y,k)-calc(x-1,k));
else
{
x=changetwo(x,b);
y=changetwo(y,b);
printf("%d\n",calc(y,k)-calc(x-1,k));
}
return 0;
}</span>