HDU:5969 最大的位或(數學,二進制)

最大的位或

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1181    Accepted Submission(s): 476


Problem Description
B君和G君聊天的時候想到了如下的問題。
給定自然數l和r ,選取2個整數x,y滿足l <= x <= y <= r ,使得x|y最大。
其中|表示按位或,即C、 C++、 Java中的|運算。
 

Input
包含至多10001組測試數據。
第一行有一個正整數,表示數據的組數。
接下來每一行表示一組數據,包含兩個整數l,r。
保證 0 <= l <= r <= 1018
 

Output
對於每組數據輸出一行,表示最大的位或。
 

Sample Input
5 1 10 0 1 1023 1024 233 322 1000000000000000000 1000000000000000000
 

Sample Output
15 1 2047 511 1000000000000000000
 

Source
 

Recommend
jiangzijing2015

解題思路:一個數a與另一個b進行或運算,那麼結果肯定大於等於其中任意一個。這題讓求一個最大的異或結果,那麼其中一個數肯定得選右區間才能使結果儘可能最大。
這樣一個數就確定了,那麼另一個數怎麼確定呢?如果l與r的位數不同,那麼從l變r的過程中一定有個全1的位數爲l的數,與r或運算後結果爲全1且位數與r相同,這種情況好算,直接2^(r的位數)-1即可。如果l與r的位數一樣的話,假設r的二進制形式爲110010,l的二進制形式爲100101,那麼從l到r上,從高位向低位逐位比較,如果l和r不是一個數,那麼一定存在一位中l的這位爲0,r的這位爲1,接着將l的這0位以後的低位全變成1,即得到想要的那個數,然後與r或運算即可。(因爲r的這位爲1,l的這位爲0,那麼l這位後全變1所得的數肯定還是小於r的,說不清反正好好理解理解,舉8~15這些數字的2進制形勢看看理解理解)。
代碼如下:
#include <cstdio>
#include <cmath>
#include <cstring>
long long l,r;
long long a[64],b[64],c[64];
long long Pow(long long x,int y)
{
    long long sum = 1;
    for(int i = 1 ; i <= y ;i++) 
	{
        sum *= x;
    }
    return sum;
}
long long wei(long long x)
{
	long long cnt=0;
	if(x==0)
	{
		return 1;
	}
	while(x)
	{
		cnt++;
		x=(x>>1);
	}
	return cnt;
}
void dabiao()
{
	long long a1=l,a2=r;
	memset(a,0,sizeof(a));
	memset(b,0,sizeof(b));
	memset(c,0,sizeof(c));
	int cnt=0;
	while(a1)
	{
		a[cnt++]=a1%2;
		a1=(a1>>1);
	}
	cnt=0;
	while(a2)
	{
		b[cnt++]=a2%2;
		a2=(a2>>1);
	}
	cnt--;
	int pos=-1;
	for(int i=cnt;i>=0;i--)
	{
		if((a[i]!=b[i])&&a[i]==0)
		{
			pos=i;
			break;
		}
	}
	for(int i=cnt;i>=pos;i--)
	{
		c[i]=a[i];
	}
	for(int i=pos-1;i>=0;i--)
	{
		c[i]=1;
	}
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%lld%lld",&l,&r);
		long long lwei=wei(l);
		long long rwei=wei(r);
		if(lwei==rwei)
		{
			dabiao();
			long long ans=0;
			for(int i=0;i<lwei;i++)
			{
				ans=ans+c[i]*Pow(2,i);//這裏比較坑,pow好像不能用longlong,手寫一個才能過 
			}
			printf("%lld\n",(ans|r));
		}
		else
		{
			long long ans=1;
			while(rwei--)
			{
				ans=ans*2;
			}
			ans=ans-1;
			printf("%lld\n",ans);
			
		}
	}
	return 0;
} 


發佈了277 篇原創文章 · 獲贊 20 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章