题目链接:点击打开链接
//二进制表示的数 的数位dp
#include<stdio.h>
#include<string.h>
#define ll long long
ll dp[40][40][2];//dp[pos][s][pre]存 位置在pos 前面出现过s个1 1相邻的情况 二进制的前一位是pre 的状态的答案
int digit[40];
ll dfs(int pos,int s,int pre,int doing)//位置在pos 前面出现过s个1 1相邻的情况 二进制的前一位是pre doing 标记是否为上界
{
if(pos==-1)return s;
if(!doing && dp[pos][s][pre]!=-1)return dp[pos][s][pre];//记忆化
int End,i;
ll ans=0;
End=doing ? digit[pos]:1;
for(i=0;i<=End;i++)
{
if(pre==1&&i==1)//前面一位是1 当前一位也是1 s+1
ans+=dfs(pos-1,s+1,1,doing && i==End);
else if(i==1)//前面一位不是1 当前一位是1 s不加 pre标记为1
ans+=dfs(pos-1,s,1,doing && i==End);
else// 其他情况 pre为0(因为二进制只有0 1)
ans+=dfs(pos-1,s,0,doing && i==End);
}
if(!doing)
dp[pos][s][pre]=ans;
return ans;
}
ll solve(ll x)
{
int l=0;
memset(dp,-1,sizeof(dp));
memset(digit,0,sizeof(digit));
while(x>0)
{
digit[l++]=x%2;//将当前数字按二进制存起来
x=x/2;
}
dfs(l-1,0,0,1);
}
int main()
{
int t,v=1;
ll n;
scanf("%d",&t);
while(t--)
{
scanf("%lld",&n);
printf("Case %d: %lld\n",v++,solve(n));
}
return 0;
}