题目链接:http://acm.hnu.cn/online/?action=problem&type=show&id=13030
题目意思:给你A B问A -- B之间的二进制表示中1的个数,包括A B本身。
规模: 1 ≤ A ≤ B ≤ 1016
数位dp,第一次深入理解数位dp的含义,总的来说,更具题目意思总结规律。
我们用dp(x)表示1-x的二进制表示1的个数。那么解就等于dp(B)-dp(A-1);
1 1
2 10
3 11
4 100
5 101
6 110
7 111
8 1000
9 1001
我们看,假设求dp(9),那么,找到小于9的最大2的幂的整数,是m=8,那么 dp(9) = dp(8-1)+tmp;
那么tmp等于多少呢??观察,8-9前面多了2个1,为9-(8-1)得到,这是因为离m最近,且大了多少个1,这是肯定的。
其次,9-8=1,9比8大1,因此,dp(1)就是后面那部分多的1的个数了。
最后 dp(n) = n-(m-1) + dp(m-1) +dp(n-m);
#include<iostream>
#include<cstdio>
#include<map>
#define LL long long
#define rt return
using namespace std;
map <LL,LL> mapt;
LL dp(LL x){
if(mapt.find(x)!=mapt.end())rt mapt[x];
if(x<=0)rt 0;
LL cnt=0,n=x;
while(x){
x/=2;
cnt++;
}
cnt--;
LL m=1;
while(cnt--)m*=2;
LL a=n-(m-1);
LL b=dp(m-1);
mapt[m-1]=b;
LL c=dp(n-m);
rt a+b+c;
}
int main(){
LL x,y;
while(~scanf("%I64d%I64d",&x,&y)){
printf("%I64d\n",dp(y)-dp(x-1));
}
return 0;
}