单点时限: 1.0 sec
内存限制: 256 MB
Cuber QQ 正在刷 EOJ 上的水题,他正在做的一道题目是这样的。
给定一个正整数 x :
如果 x 是奇数的话,则变幻成 x−1 ;
如果 x 是偶数的话,则变幻成 x2 。
如此往复地执行这个操作,直到 x 变为 1 。
显然这对于 Cuber QQ 来说过于简单了。于是 Cuber QQ 根据这个发明了一个序列,称为变幻序列, x -变幻序列指的是,从 x 作为变幻的开始,一直变幻到 1 所构成的序列,例如 7 -变幻序列是 {7,6,3,2,1} ; 10 -变幻序列是 {10,5,4,2,1} 。
而现在 Cuber QQ 在纸上写出了所有 1 到 n 变幻序列,他分别统计了每一个数在这些序列中出现的次数,例如当 n=4 的时候,四个序列分别是 [1]={1},[2]={2,1},[3]={3,2,1},[4]={4,2,1} ,则 数 1 出现了 4 次,数 2 出现了 3 次 ,数 3 出现了 1 次 ,数 4 出现了 1 次。
现在 Cuber QQ 想知道最大的数 x 满足 x 在所有 1 到 n 变幻序列中至少出现了 k 次。
输入格式
第一行包含一个整数 T(1≤T≤104) ,表示数据组数。
对于每一组数据包含两个整数 n,k(1≤k≤n≤1018) ,含义如题面所述。
输出格式
对于每一组数据,输出一行一个整数表示答案。
样例
input
4
4 1
4 2
4 3
4 4
output
4
2
2
1
思路:对于每个数字 x 来说,它可以由自己变幻一次,也可以由某些更大的数字变幻得到。
简单的来说,当 x 是偶数时,x 会被 x+1 和 2x ,以及其2的整数倍变幻得到,即2x,2x+1,2x+2,2x+3,会发现对于每一个k,可以变换成x有:kx,kx+1…kx+2^k-1,当 x 是奇数的时候会被 x自己变幻一次,及2x,2x+1,归纳得到:kx,kx+1…kx+k-1。那么,很容易的发现,如果将奇数和偶数独立开来考虑的话,是满足单调性的。
于是我们考虑对奇数和偶数分别二分确定最大值,然后取两者中的较大值作为答案即可。
我们考虑对于每一个k,可以变幻为 x 的 k ∗ x + b 的最大个数,其中k为2的整数次幂。
k | 1 | 2 | 4 | 2^m |
---|---|---|---|---|
x是奇数 | x | 2x,2x+1 | 4x,4x+1,4x+2,4x+3 | 最多为2^m个 |
x是偶数 | x,x+1 | 2x,2x+1,2x+2,2x+3 | 4x,4x+1,4x+2…4x+7 | 最多为2^(m+1)个 |
/*
考虑 x 是∈ [1,n],所以对于每一个 k,可以变幻为 x 的最大个数:
x是奇数:min(n-k*x,k-1)+1
x是偶数:min(n-k*x,2*k-1)+1
*/
#include<iostream>
#define ll long long
using namespace std;
ll n,k;
ll count=0;
ll f(ll x,ll k) {
if(x*k>n)
return 0;
ll res=n-x*k;
if(x%2==1)//奇数时
return min(res,k-1)+1+f(x,k*2);
else//偶数时
return min(res,2*k-1)+1+f(x,k*2);
}
int main() {
int t;
cin>>t;
while(t--) {
cin>>n>>k;
if(k==n)
cout<<1<<endl;
else if(k==n-1)
cout<<2<<endl;
else {
ll l = 0,h = (n+2)/2;
ll mid;
while(h-l>1) {
mid = (l+h)/2;
ll p = f(mid*2,1);
if(p<k) h = mid;
else l = mid;
}
ll ans = f(l*2+1,1);
if(ans>=k)
printf("%lld\n",l*2+1);
else
printf("%lld\n",l*2);
}
}
return 0;
}