POJ 3252

折腾了很久。

注意到,每一个数总是这样的形式的:1010101100100。。

如,当110000到111000时,我们可以看成是从110000到110111的计数。最后特判111000即可。这时,我们需要记下前三们110中1与0的个数之差,以决定后三位取0的个数。所以,不妨预处理出0,1,10,100,1000....等两数之间的ROUND数,再按上面说的按位计数即可。

今天2015.2.7在做数位DP时又碰上这题了,重新写一写。

举个例子,当1100000到1110000时,我们可以看成是从110000到110111的计数。最后特判111000即可。例如处理后三位的时候,这时我们需要记录下110这前三位0与1的个数的差-1,来决定后四位0与1的个数的差1。例如决定0比1多1时,这时可以运用组合数学的知识,那么只需在预出理出来的ROUND(所以,不妨预处理出0,1,10,100,1000....等两数之间的ROUND数,再按上面说的按位计数即可。)中,减去多于1的部分即可,。如果是K,则需要减去1~k部分。

#include <iostream>
#include <cstdio>
#include <algorithm>
#define LL __int64
using namespace std;

LL pd[35];
LL num[35];

LL myc(int n,int r){
	LL sum=1;
	for(int i=1;i<=r;i++)
	sum=sum*(LL)(n+1-i)/(LL)i;
	return sum;
}

void initial(){
	pd[0]=1; 
	pd[1]=0; 
	LL tmp,sum;
	int r;
	for(int i=2;i<=33;i++){
		r=(i-1)/2+1;
		tmp=myc(i-1,r);
		pd[i]=tmp;
		for(int j=r+1;j<=i-1;j++){
			tmp=tmp*(LL)(i-1-j+1)/(LL)j;
			pd[i]+=tmp;
		}
	}
}

LL how(LL as){
	LL ret=0;
	while(as){
		ret++;
		as=(as>>1);
	}
	return ret;
}

LL ABS(LL a){
	return a>=0?a:-a;
}

LL confer(LL as,LL bt,int pos){
	LL res=0;
	for(LL i=0;i<bt;i++)
	res+=pd[i];
	LL ans=1;
	LL tmp=(1LL<<(bt-2));
	LL r;
	for(LL i=bt-1;i>0;i--){
		if(tmp&as){
			ans++;
		}
		else ans--;
		if(tmp&as){
		//	if(i-1==0) continue;
			if(ans-2>=0){
				r=(ans-2+i-1);
				if(r%2) r=r/2+1;
				else r=r/2;
			}
			else{
				r=i-1-(ans-2);
				if(r%2) r=r/2+1;
				else r=r/2;
				r=r-ABS(ans-2);
				if(r<=0) r=0;
			}
			LL sum=myc((int)i-1,(int)r);
			res+=sum;
			for(LL k=r+1;k<=i-1;k++){
				sum=sum*(i-k)/k;
				res+=sum;
			}
		}
		tmp>>=1;
	}
	if(ans<=0&&pos==2) res++;
	return res;
}

int main(){
	initial();
	LL a,b;
	while(scanf("%I64d%I64d",&a,&b)!=EOF){
		LL bta=how(a),btb=how(b);
		bta=confer(a,bta,1);
	//	cout<<bta<<endl;
		btb=confer(b,btb,2);
		printf("%I64d
",btb-bta);
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/jie-dcai/p/3992998.html