/*Description
给定L,R,输出X,X在[L,R]中,且其为转化成二进制后1的总数最多的那个数(同时存在多个解,输出最小的那个)。
Input
第一行为询问个数n,(1<=n<=10000).
接下来有n行.每行有两个数为L,R(0<=L<=R<=10^18)
Output
每个询问输出一个答案。
Sample Input
3
1 2
2 4
1 10
Sample Output
1
3
7
Hint
将每个数转化成二进制数:
1->1
2->10
3->11
4->100
5->101
10 1010 11 1011
2的最高次方-1或减去其位数加一
现在有三种情况, 2的counter次 就是后面除以2的i
如果a在i的counter次的左边那么最小值就是i的couter次方-1了
如果a大与i的counter次方,则最大值就是b
*/
#include <stdio.h>
typedef long long ll;
ll array[100];
int j = 0;
ll dfs(int j,ll a,ll b){
int i;
for (i = 1;i <= b+1;i *= 2);
i /= 2;
if (a < i)return i-1;
else {
a -= i;
b -= i;
array[j] = i;
j ++;
return dfs(j,a,b);
}
}
ll dfc(int j,ll a,ll b){
int i;
for (i = 1;i <= b+1;i *= 2);
i /= 2;
if (a < i)return j;
else {
a -= i;
b -= i;
j ++;
return dfc(j,a,b);
}
}
int main()
{
int n;
scanf("%d",&n);
//n = 10;
ll a,b,i,result;
while (n --){
scanf("%lld %lld",&a,&b);
ll result = dfs(j,a,b);
j = 0;
int i;
j = dfc(j,a,b);
for (i = 0;i < j;i ++)
result += array[i];
j = 0;
printf("%lld\n",result);
}
return 0;
}
有点难受啊,遍了一个题目,结果有这么多问题,递归函数中如何传值(我要传的是两个值)
我的算法有点点奇怪,但是,主要还是我原先那个简单问题的思考。
错误方式: 时间时 time limit
现在经过了高人指点后,我的思路又进行了优化。
#include <stdio.h>
using namespace std;
long long dfs(long long a,long long b){
long long i;
for (i = 1;i <= b+1;i *= 2);
i /= 2;
// i 是以下的第一2n - 1
if (a < i)return i-1;
else {
int t;
for (t = 1;i <= b;i += t,t *= 2);
i = i - t/2;
int c;
t = t/2;
if (i < a)
for (c = t;i < a;i += c){
c /= 2;
if (c == 0){
t = t/2;
c = t;
}
}
return i;
}
}
int main()
{
int t;
scanf("%d",&t);
while (t --){
long long a,b;
scanf("%lld %lld",&a,&b);
printf("%lld\n",dfs(a,b));
}
return 0;
}
强行一波c++这不重要。
前一部分的思路并没有变,一定是找。。。。自己想。
但是后面就有了优化。
看看多么艰辛啊,
第一部分的优化是先开始从i即(小于等于b的最大二的倍数)
但是后面我是利用递归进行深入分解,
时间就炸了,还引出了一个关于递归与全局变量的问题,
而高手是找规律,从
例子 i = 1000(二进制)
那么就从1001开始
1011
1111
寻找一个比b小的最大i
然而又是a
还得保证a<i
只能又进行奇怪的循环了
---------------------------------------------------咦?为什么我感觉我原来的方法更简单。
看来此题未解,我们还得算账。