CCPC 2016安徽大学站 I 朋友 hdu 5969

来源:互联网 发布:伴奏升降调软件 编辑:程序博客网 时间:2024/04/30 09:48
B君和G君聊天的时候想到了如下的问题。 
给定自然数l和r ,选取2个整数x,y满足l <= x <= y <= r ,使得x|y最大。 
其中|表示按位或,即C、 C++、 Java中的|运算。
Input
包含至多10001组测试数据。 
第一行有一个正整数,表示数据的组数。 
接下来每一行表示一组数据,包含两个整数l,r。 
保证 0 <= l <= r <= 10181018
Output
对于每组数据输出一行,表示最大的位或。
Sample Input
51 100 11023 1024233 3221000000000000000000 1000000000000000000
Sample Output
1512047511

1000000000000000000

中文题目,很简单的题意。

题目分析:因为数据偏大,很显然用暴力会超时,果不其然我超时了一发,以为这是比赛场上的签到题可以无

做,没想到还是太年轻。然后来分析,因为给你l和r,所以位或的值肯定是可以用r和l到r的一个数表示的,那

现在我们考虑,先把l和r都换成二进制,然后从高位向低位遍历,并且l和r的位数要一致,不一致要用0补齐,

一旦有他们在同一位时l为0,r为1,立马停止,将此位后面的r全部补为1,所得到的值就是答案。

#include <cstdio>#include <cstring>#include <iostream>using namespace std;long long pow(long long a,long long b){for(int i=2;i<=b;i++){a=a*2;}if(b == 0) return 1;return a;}int main(){long long l,r;int n;long long ans=0;scanf("%d",&n);    int a[1100],b[1100],c[1100];    while(n--){    scanf("%lld%lld",&l,&r);    int i=1,j=0;    ans=0;    long long ac=l,bc=r;    memset(a,0,sizeof(a));    memset(b,0,sizeof(b));    memset(c,0,sizeof(c));    while(l){    a[i++]=l%2;    l=l/2;}    for(j=1;j<i;j++)       swap(a[i-j],b[j]);//对l十进制变为二进制,用b存储  long long zz,z=i; zz=z;     long long p;    i=1;j=1;    memset(a,0,sizeof(a));    while(r){     c[i++]=r%2; r=r/2;    }    for(j=1;j<i;j++)   swap(c[i-j],a[j]);   p=i;//对r十进制变为二进制,用a存储     memset(c,0,sizeof(c));    if(p>=zz){    for(int m=1;m<zz;m++,z--)      c[p-z+1]=b[m];}//保证c数组和b数组的位数相同if(ac == bc ) printf("%lld\n",(ac|bc));//如果两数相等,则直接输出 else{        for(int k=1;k<p;k++){         if(a[k]==1 && c[k]==0){        for(int q=k;q<p;q++)           a[q]=1;       break;       }            }        for(int i=1;i<p;i++)            ans+=a[i]*pow(2,p-i-1);//二进制变十进制              printf("%lld\n",ans);   }}return 0;} 


0 0
原创粉丝点击