• spoj1182 Sorted bit squence/[USACO2003 Dec]Cow Queueing


    题目链接:SPOJ的->http://www.spoj.com/problems/SORTBIT/

    题目大意:

    约翰给每头奶牛用一个数字编号,这些奶牛在集合时,会将自己编号转换成二进制表示,并按照以下规则排队:
    • 首先,编号的二进制中1 出现次数较少的排在队伍的前面;
    • 其次,如果1 的数量一样多,那么编号较小的排在前面;
    举个例子,从4 到15,有12 个数字,顺序应该是
    100; 1000; 101; 110; 1001; 1010; 1100; 111; 1011; 1101; 1110; 1111
    假设编号在A到B之间的所有奶牛都在排队,那么这个队伍中排在第K 位的奶牛编号应该是多少呢?


    注意:USACO的保证都是非负数0 ≤A≤B<10^9;而spoj上可能有负数但A,B同正同负 -2^31 ≤ A ≤ B ≤ 2^31-1,而且若为负数,则其二进制与其相反数的二进制的和为2^32。


    题解:

    组合+二分+数位DP

    下面的都是最低位为第0位(还是1..???忘了..自己看)。

    设f[i][j][k]表示在0~i中,做到了第j位(二进制),要放k个1有多少种方案(即有多少个这样的数)。

    首先,如果i在这位上有1,那么我在这一位取0的话就不在上限边缘,就可以在j-1个位置上随便摆k个1,有C(j-1,k)种方案;而我若取了1,那就为f[i][j-1][k-1]。

    而如果i在这位上是0的话,那我也只能取0了啊,所以为f[i][j-1][k]。

    这个有什么用呢?

    我们先找到排第K位的奶牛有几个1。知道↑之后不用说怎么做吧。

    然后在范围[A,B]中二分,使排位不断接近K。因为是用左端点不断靠近答案,所以最后输出l。

    USACO的输入输出都是二进制,而spoj的输入输出都是十进制(而且负数要搞回负数..(提醒了我负数这一回事

    如果都是负数的话,因为其二进制与其相反数的二进制的和为2^32,那么我们把这个数+2^32,最后再减回来是一样的。

    为什么呢?假设这个数为x,相反数为-x,相反数为正数所以是正常的...意思就是(-x)10=(-x)2诶就是说-x的二进制表示的大小和原数相同。

    那么 有 -x +(x)2 = 2^32 --> (x)2=x+2^32。

    就得到了它的二进制了。其他的照做就好了。 

    p.s.下面的代码是spoj的。如果要交USACO的话就把多组数据删了,注释的弄回来,“=====”之间的注释掉。

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    
    LL bit[40],C[40][40];
    char s[40];
    const LL MX=1LL<<32;
    void redc()//预处理组合C(i,j)
    {
    	C[0][0]=1;
    	for (int i=1;i<=32;i++)
    	{
    		C[i][0]=1;
    		for (int j=1;j<=i;j++)
    		  C[i][j]=C[i-1][j]+C[i-1][j-1];
    	}
    }
    void dels(LL &x)//这是处理二进制输入的
    {
    	int len=strlen(s);x=0;
    	for (int i=len-1,k=0;i>=0;i--,k++)
    	 x+=bit[k]*(s[i]-'0');
    }
    LL dfs(LL x,int w,int k)//就是上面说的f[x][w][k]。不过没有存下来而已。意义一样
    {
    	if (w==0 && k==0) return 1;
    	if (x<0 || w==0 || k<0) return 0;
    	LL p=1LL<<(w-1);
    	if (x&p) return C[w-1][k]+dfs(x,w-1,k-1);
    	return dfs(x,w-1,k);
    }
    int main()
    {
    	//freopen("cowq.in","r",stdin);
    	//freopen("cowq.out","w",stdout);
    	int i,T;LL l,r,now,sum,K;
    	LL A,B,mid,jl,ind;bit[0]=1;
    	for (i=1;i<=32;i++) bit[i]=bit[i-1]*2;
    	redc();
    	scanf("%d",&T);
    	while (T--)
    	{
    		// scanf("%s
    ",s);dels(A);
    		// scanf("%s",s);dels(B);
    		//-----------------------
    		scanf("%lld%lld",&A,&B);
    		scanf("%lld",&K);
    		bool pd=0;
    		if (A<0 || B<0) A+=MX,B+=MX,pd=1;
    		if (A>B) {LL t=A;A=B;B=t;}
    		//------------------------
    		sum=now=0;
    		for (i=0;i<=31;i++)
    		{
    			now=dfs(B,32,i)-dfs(A-1,32,i);
    			if (sum+now<K) {sum+=now;ind=i;}
    			else {K=K-sum;break;}
    		}ind++;//找排第K的有ind个1
    		l=A;r=B;jl=dfs(A-1,32,ind);
    		while (l<r)//二分
    		{
    			mid=(l+r)>>1;
    			now=dfs(mid,32,ind)-jl;
    			if (now<K) l=mid+1;
    			else r=mid;
    		}
    		//-----------------------
    		if (pd) l=l-MX;
    		printf("%lld",l);
    		//-----------------------
    		// bool pd=0;
    		// for (i=32;i>=0;i--)
    		 // if (l&bit[i])
    		 // {
    			// printf("1");
    			// pd=1;
    		 // }else if (pd) printf("0");
    		printf("
    ");
    	}
    	return 0;
    }


  • 相关阅读:
    比较两个树是否相同
    将一个字符串转换成一个整数
    求数组中第一个重复数字
    Redis之哨兵机制(sentinel)——配置详解及原理介绍
    ==和equals的区别
    求一个数的立方根
    检测应用版本
    【转】UITableViewCell自适应高度 UILabel自适应高度和自动换行
    iOS7中Cell高度 Label高度自适应
    MarsEdit 快速插入代码
  • 原文地址:https://www.cnblogs.com/Euryale-Rose/p/6527828.html
Copyright © 2020-2023  润新知