Description
对于一串自然数序列0,1,2,3,4,5,6......,n。 冰神给了你一个任务,就是求,0到n中,所有自然数的二进制码中的‘1’的个数 举个例子:当n=5的时候 十进制数 二进制数 ------------------------- 0 0 1 1 2 10 3 11 4 100 5 101 0,1,10,11,100,101这5个二进制数中间共有7个‘1’出现,所以当n=5的时候,答案为7
Input
输入数据多组,读入EOF的时候结束 每一行输入一个数n
Output
对于每一个输出,答案占一行。
2 3 5 1164 20071010 20100512 835672545
Case 1: 2 Case 2: 4 Case 3: 7 Case 4: 5744 Case 5: 239720074 Case 6: 240071643 Case 7: 12245574353
Hint
输入虽然只有2^32,但是输出会超出int,所以请选择合适的数据类型
【题意】如题。
【分析】数位dp。
【状态表示】dp[i]表示的是I位的二进制数里面1的个数,那么容易知道dp[1]=1,dp[i] = 2*dp[i-1] + (1<<(i-1));预处理dp数组之后,对输入的数n,从最高位到最低位,我们可以这样做,判断当前二进制中的这一位是否为1,如果是为1的话,那么ans += dp[i]+cur_ans*(1<<i),(自行理解吧,我也很晕!)
【AC代码】
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
typedef long long LL;
LL dp[33];
int main()
{
//Init.
dp[0]=1;
dp[1]=1;
for(int i=2; i<=33; i++)
{
dp[i] = 2*dp[i-1]+(1<<(i-1));
}
for(int i=1; i<=33; i++)dp[i]++;
LL n;
int cas=1;
while(~scanf("%lld",&n))
{
LL ans=0;
int cur_ans=0;
for(int i=33; i>=0; i--)
{
int tmp = (n>>i)%2;
if(tmp==1)
{
ans+=dp[i]+(1ll)*cur_ans*(1<<i);
cur_ans++;
}
}
printf("Case %d: %lld\n",cas++,ans);
}
return 0;
}