题目连接: 题目连接ios
题意:若是一个数二进制n有k位1,那么f1[n] = k,若是k有s位二进制1,那么f2[n] = f1[k] = s. 如此往复,直到fx[n] = 1,此时的x就是n的”K值“,如今要求[L,R]内的”K值“为X的数有多少个。(1<=L<=R<=10^18)ide
解法:首先能够看到10^18最多只有61位左右的数,因此咱们只需处理1~61之间每一个数有多少个1,便可知道1~61之间每一个数”K值“是多少。spa
而后就将求[L,R]之间的个数变成求[1,R]-[1,L-1],因此咱们只需数出对于每一个数n,[1,n]之间有多少个数的”K值“为X便可。3d
对于二进制来讲,能够这样搜索出来:code
好比<=101001,要知足有k个1的数的个数,那么咱们从高位往低位扫,扫到第一个1,那么如今有两种状况:blog
1.此处放1:那么就等于求<=1001时放k-1个1的数的个数递归
2.此处放0:那么后面就随便放了,为C[5][k]get
因此如此递归的搜索就可得出答案,也能够用DP作。string
代码:it
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> #define ll long long using namespace std; int Count(ll state) { int cnt = 0; while(state) { if(state & 1LL) cnt++; state >>= 1; } return cnt; } int WEI(ll state) { int cnt = 0; while(state) { cnt++; state >>= 1; } return cnt; } ll C[100][100]; int in[67]; void init() { C[0][0] = 1; for(int i = 1; i < 90; i++) { C[i][0] = 1; for(int j = 1; j <= i; j++) { C[i][j] = C[i - 1][j] + C[i - 1][j - 1]; } } memset(in,0,sizeof(in)); in[1] = 0; for(int i=2;i<=61;i++) in[i] = in[Count(i)]+1; } int X; ll get(ll state,int cnt) { if(state < 0) return 0; int len = WEI(state); if(len < cnt) return 0; // not enough if(cnt == 0) return 1; // no demand return get(state-(1LL<<(len-1)),cnt-1) + C[len-1][cnt]; } ll getsum(ll R,ll L) { ll ans = 0; for(int i=1;i<=61;i++) if(in[i]+1 == X) ans += get(R,i)-get(L-1,i); return ans; } int main() { init(); int i,j; ll L,R; while(scanf("%lld%lld%d",&L,&R,&X)!=EOF && L+R+X) { ll ans = 0; if(X == 0 && L == 1LL) { puts("1"); continue; } if(X == 1 && L == 1LL) ans--; //1's binary code is 1, but 1 is not in (X==1) ans += getsum(R,L); cout<<ans<<endl; } return 0; }