刚开始的时候有点想法,但是没有具体,主要是一开始题目看错了,认为给的这一段区间可能包含了正数和负数,该打,题目都可以看错,一直以来的经验教训都没有吸取。
代码中去掉最高位的方法还是相当的不错的,至于以后二进制的变形,应该都可以参考这其中的技巧。
代码:
View Code
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 typedef long long LL; 6 int const N = 40; 7 int f[N][N],n,m,k; 8 void pre() 9 { 10 f[0][0]=1; 11 for(int i=1;i<=31;i++) 12 { 13 f[i][0]=f[i-1][0]; 14 for(int j=1;j<=i;j++) 15 f[i][j]=f[i-1][j]+f[i-1][j-1]; 16 } 17 } 18 int getsum(int x,int k) 19 { 20 int tot=0,ret=0; 21 for(int i=31;i>0;i--) 22 { 23 if(x&(1<<i)) 24 { 25 tot++; 26 if(tot>k)break; 27 x^=(1<<i); 28 } 29 if((1<<i-1)<=x) 30 ret+=f[i-1][k-tot]; 31 } 32 if(tot+x==k)ret++; 33 return ret; 34 } 35 int cal(int l,int r,int k) 36 { 37 int i; 38 for(i=1;i<=31;i++) 39 { 40 int co=getsum(r,i)-getsum(l-1,i); 41 if(co>k)break; 42 k-=co; 43 } 44 45 int lf=l,rt=r,mid; 46 while(lf<rt) 47 { 48 mid=(int)(((LL)lf+(LL)rt)>>1); 49 int co=getsum(mid,i)-getsum(l-1,i); 50 if(co<k) 51 lf=mid+1; 52 else 53 rt=mid; 54 } 55 return lf; 56 } 57 int main() 58 { 59 int T; 60 scanf("%d",&T); 61 pre(); 62 while(T--) 63 { 64 scanf("%d %d %d",&m,&n,&k); 65 if(n==0&&m==0) 66 { 67 printf("0\n"); 68 continue; 69 } 70 if(m>=0) 71 { 72 if(m==0) 73 k--,m++; 74 if(k==0) 75 printf("0\n"); 76 else 77 printf("%d\n",cal(m,n,k)); 78 } 79 else 80 { 81 if(n==0) 82 k--,n--; 83 m&=(~(1<<31)); 84 n&=(~(1<<31)); 85 printf("%d\n",(1<<31)|cal(m,n,k)); 86 } 87 } 88 return 0; 89 }