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\n",btb-bta); } return 0; }