Let's denote as the number of bits set ('1' bits) in the binary representation of the non-negative integer x.
You are given multiple queries consisting of pairs of integers l and r. For each query, find the x, such that l ≤ x ≤ r, and is maximum possible. If there are multiple such numbers find the smallest of them.
The first line contains integer n — the number of queries (1 ≤ n ≤ 10000).
Each of the following n lines contain two integers li, ri — the arguments for the corresponding query (0 ≤ li ≤ ri ≤ 1018).
For each query print the answer in a separate line.
3 1 2 2 4 1 10
1 3 7
The binary representations of numbers from 1 to 10 are listed below:
110 = 12
210 = 102
310 = 112
410 = 1002
510 = 1012
610 = 1102
710 = 1112
810 = 10002
910 = 10012
1010 = 10102
分两种情况考虑:
1.l和r的二进制拆分之后位数不同:
如果r是11111...那么答案就是r;否则是答案是11111..比l少1位
2.l和r的二进制拆分之后位数相同:
从前往后扫到不相同的那一位k,如果r从k以后全是1,答案就是r;否则答案是前k位+1111...(k+1位到最后一位都是1)
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#define LL long long
using namespace std;
int a[3][1000],n;
void chai(LL x,int k)
{
a[k][0]=0;
while (x)
{
a[k][0]++;
int s=a[k][0];
if (x&1) a[k][s]=1;
else a[k][s]=0;
x>>=1;
}
}
int main()
{
int n;
cin>>n;
while (n--)
{
LL l,r;
cin>>l>>r;
if (l==r)
{
cout<<l<<endl;
continue;
}
chai(l,0);
chai(r,1);
if (a[0][0]<a[1][0])
{
LL ans=0,b=1;
for (int i=1;i<a[1][0];i++)
ans+=b,b<<=1LL;
if (ans+b==r) ans=r;
cout<<ans<<endl;
}
else
{
int k=0;
for (int i=a[0][0];i;i--)
{
if (a[0][i]!=a[1][i])
{
k=i;
break;
}
}
LL ans=0,b=1;
for (int i=1;i<k;i++)
ans+=b,b<<=1LL;
int ok=1;
for (int i=1;i<=k;i++)
{
if (!a[1][i]) ok=0;
}
if (ok) ans+=b;
b<<=1LL;
for (int i=k+1;i<=a[0][0];i++)
ans+=(b*a[0][i]),b<<=1;
cout<<ans<<endl;
}
}
return 0;
}
x=aj*k+b,k相同,要让b最大则让x最大。
我们枚举k,要找到>aj*k且<aj*(k+1)的最大数。
就相当于找最接近aj*(k+1)的数,那么我们预处理出m[i]表示<=i的最大数是几。
(注释掉的是nlognlogn的做法,会TLE)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <set>
#define mp make_pair
#define M 200000+5
using namespace std;
int n,a[M],v[2000000+5],m[2000000+5];
set<pair<int,int> > s;
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
sort(a+1,a+1+n);
int tot=0;
for (int i=2;i<=n;i++)
if (a[i]!=a[i-1])
{
a[++tot]=a[i-1];
}
a[++tot]=a[n];
n=tot;
for (int i=1;i<=n;i++)
v[a[i]]=a[i];
for (int i=1;i<=a[n]*2;i++)
m[i]=max(m[i-1],v[i]);
int ans=0;
for (int i=1;i<n;i++)
for (int j=a[i]*2;j<=a[n]*2;j+=a[i])
ans=max(ans,a[i]+m[j-1]-j);
/*for (int i=1;i<n;i++)
s.insert(mp(a[n]/a[i]*a[i],i));
int ans=0;
for (int i=n;i>1;i--)
{
if (a[i-1]<=ans) break;
ans=max(ans,a[i]-s.begin()->first);
int fi=s.rbegin()->first,se=s.rbegin()->second;
while (i>2&&fi>a[i-1])
{
s.erase(mp(fi,se));
if (se<i-1)
s.insert(mp(a[i-1]/a[se]*a[se],se));
fi=s.rbegin()->first,se=s.rbegin()->second;
}
}*/
printf("%d\n",ans);
return 0;
}
ans表示当前的最大答案是多少;
s表示(前k个数的最大答案-a[k+1])的最大值;
l表示(前p个数的最大答案+a[p+1])的最大值;
那么当扫描到a[i]时,更新s,l,ans(见代码)
#include <iostream>
#include <algorithm>
#include <cstdio>
#define LL long long
using namespace std;
LL ans,s,l;
int main()
{
int n;
scanf("%d",&n);
LL x;
scanf("%I64d",&x);
ans=0,s=-x,l=x;
for (int i=1;i<n;i++)
{
scanf("%I64d",&x);
if (ans-x>s)
s=ans-x;
if (ans+x>l)
l=ans+x;
ans=max(ans,max(s+x,l-x));
}
cout<<ans<<endl;
return 0;
}
感悟:
D题值得借鉴,简单巧妙~