【spoj1182/usaco-Cow Queueing, 2003 Dec-二进制编号】数位dp
题意:定义新的排序:先按一个数中二进制中1的个数从小到大排序,如果1的个数相同则按数的大小从小到大排序。问[A,B]之间有第K大的数是哪个。-2^31<=A,B<=2^31(A,B必定同正负,负数的二进制与它相反数的二进制相加=2^32)
题解:
负数可以直接+2^31-1转化为正数。
先确定答案中1的个数:依次统计区间[m,n]内二进制表示中含1的数量为0,1,2,…的数,直到累加的答案超过k,则当前值就是答案含1的个数,假设是ind。
怎么求?就先确定当前位填什么,然后后面还有多少个1可以填,组合数弄一下。
同时,我们也求出了答案是第几个[m,n]中含ind个1的数。因此,只需二分答案,求出[m,ans]中含s个1 的数的个数进行判断即可。
这个二分需要不断往左端点靠,假设答案是ans,ans+1也含有跟ans一样的还有ind个1的数的个数。
spoj1182(输入是十进制)
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<cmath>
5 #include<iostream>
6 #include<algorithm>
7 using namespace std;
8
9 typedef long long LL;
10 const int N=50;
11 const LL MX=(1LL<<32);
12 LL X,Y,K,c[N][N];
13
14 void myswap(LL &x,LL &y){LL t;t=x;x=y;y=t;return;}
15
16 void find_c()
17 {
18 memset(c,0,sizeof(c));
19 c[0][0]=1;
20 for(int i=1;i<=35;i++)
21 {
22 c[i][0]=1;
23 for(int j=1;j<=i;j++) c[i][j]=c[i-1][j]+c[i-1][j-1];
24 }
25 }
26
27 LL find_k(LL x,int ind,int k)//0~x how many numbers has k '1's;
28 {
29 if(ind==0 && k==0) return 1;
30 if(x<0 || ind==0 || k<0) return 0;
31 LL t=1LL<<(ind-1);
32 if(x&t) return c[ind-1][k]+find_k(x,ind-1,k-1);
33 else return find_k(x,ind-1,k);
34 }
35
36 int main()
37 {
38 freopen("a.in","r",stdin);
39 // freopen("me.out","w",stdout);
40 int T;
41 scanf("%d",&T);
42 find_c();
43 while(T--)
44 {
45 scanf("%lld%lld%lld",&X,&Y,&K);
46 if(X<0) X=MX+X;
47 if(Y<0) Y=MX+Y;
48 if(X>Y) myswap(X,Y);
49
50 LL sum=0,ind=0,now,k;
51 for(int i=0;i<=31;i++)
52 {
53 now=find_k(Y,32,i)-find_k(X-1,32,i);
54 if(sum+now<K) sum+=now,ind=i;
55 else {k=K-sum;break;}
56 }
57 ind++;
58 // printf("ind = %lld k = %lld\n",ind,k);
59 LL l=X,r=Y,mid;
60 while(l<r)
61 {
62 mid=(l+r)/2;
63 now=find_k(mid,32,ind)-find_k(X-1,32,ind);
64 // printf("mid = %lld now = %lld %lld\n",mid,now,find_k(mid,32,ind));
65 if(now<k) l=mid+1;
66 else r=mid;
67 }
68 printf("%d\n",l);
69
70 }
71 return 0;
72 }
usaco (usaco上输入输出都是二进制形式)
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<cmath>
5 #include<iostream>
6 #include<algorithm>
7 using namespace std;
8
9 typedef long long LL;
10 const int N=50;
11 const LL MX=(1LL<<32);
12 LL X,Y,K,c[N][N],d[N],bit[N];
13 char s[20];
14
15 void myswap(LL &x,LL &y){LL t;t=x;x=y;y=t;return;}
16
17 void find_c()
18 {
19 memset(c,0,sizeof(c));
20 c[0][0]=1;
21 for(int i=1;i<=35;i++)
22 {
23 c[i][0]=1;
24 for(int j=1;j<=i;j++) c[i][j]=c[i-1][j]+c[i-1][j-1];
25 }
26 }
27
28 LL find_k(LL x,int ind,int k)//0~x how many numbers has k '1's;
29 {
30 if(ind==0 && k==0) return 1;
31 if(x<0 || ind==0 || k<0) return 0;
32 LL t=1LL<<(ind-1);
33 if(x&t) return c[ind-1][k]+find_k(x,ind-1,k-1);
34 else return find_k(x,ind-1,k);
35 }
36
37 LL read()
38 {
39 scanf("%s",s);
40 LL x=0;int l=strlen(s);
41 for(int i=l-1;i>=0;i--)
42 {
43 if(s[i]=='1') x+=bit[l-i-1];
44 }
45 return x;
46 }
47
48 int main()
49 {
50 // freopen("a.in","r",stdin);
51 freopen("cowq.in","r",stdin);
52 freopen("cowq.out","w",stdout);
53 find_c();
54 bit[0]=1;
55 for(int i=1;i<=31;i++) bit[i]=bit[i-1]*2;
56
57 X=read();
58 Y=read();
59 scanf("%lld",&K);
60 // printf("X = %lld Y = %lld\n",X,Y);
61 // scanf("%lld",&X,&Y,&K);
62 if(X<0) X=MX+X;
63 if(Y<0) Y=MX+Y;
64 if(X>Y) myswap(X,Y);
65
66 LL sum=0,ind=0,now,k;
67 for(int i=0;i<=31;i++)
68 {
69 now=find_k(Y,32,i)-find_k(X-1,32,i);
70 if(sum+now<K) sum+=now,ind=i;
71 else {k=K-sum;break;}
72 }
73 ind++;
74 // printf("ind = %lld k = %lld\n",ind,k);
75 LL l=X,r=Y,mid,p=find_k(X-1,32,ind);
76 while(l<r)
77 {
78 mid=(l+r)/2;
79 now=find_k(mid,32,ind)-p;
80 // if(now<k) l=mid+1;
81 if(now<k) l=mid+1;
82 if(now>=k) r=mid;
83 }
84 // printf("%d\n",l);
85 int x=0;
86 while(l)
87 {
88 d[++x]=l%2;
89 l/=2;
90 }
91 for(int i=x;i>=1;i--) printf("%d",d[i]);printf("\n");
92 return 0;
93 }