题意:
找出给定范围中满足这个条件的数的个数:这个数各个转化成2进制0个数大于1的个数。
题解:
设定状态:因为这题各个数位的关系只与0、1的个数有关,那么就可以这样dp[pos][one][zero]位数pos一的个数为one零的个数为zero满足条件数的个数。
注意前导零的问题,所以在搜索时加了特别的判断!因为二进制只有0和1,前导零是不算在这个数中零的个数上面的。
#include<stdio.h> #include<string.h> #include<algorithm> #include<iostream> #include<math.h> using namespace std; typedef __int64 lld; #define oo 0x3f3f3f3f #define digit 66 #define maxn 82 lld dp[digit][digit][digit]; int bit[digit]; lld dfs(int pos,int one,int zero,int pre0,int f) { if(pos<1) return zero>=one; if(!f&&dp[pos][one][zero]!=-1) return dp[pos][one][zero]; int last=f?bit[pos]:1; lld res=0; for(int i=0;i<=last;i++) { //pre0=0表示有前导零,pre0=1表示没有 if(pre0==0) { if(i==0) res+=dfs(pos-1,0,0,0,f&&i==last); else res+=dfs(pos-1,1,0,1,f&&i==last); } else { if(i==0) res+=dfs(pos-1,one,zero+1,pre0,f&&i==last); else res+=dfs(pos-1,one+1,zero,pre0,f&&i==last); } } if(!f) dp[pos][one][zero]=res; return res; } lld Cnt(lld n) { int len=0; while(n) { bit[++len]=n%2; n/=2; } return dfs(len,0,0,0,1); } int main() { int T; lld a,b; memset(dp,-1,sizeof dp); while(scanf("%I64d %I64d",&a,&b)!=EOF) { printf("%I64d\n",Cnt(b)-Cnt(a-1)); } return 0; }