找规律

我在打表后发现,这一题可以进行二分答案,来做。
虽然整体并不呈现单调性但是偶数和奇数却呈现单调性。
这就很方便了。
我们可以分别在偶数和奇数上进行二分答案,然后取大即可。

但是,有一个困难,那就是如何求解每次这个数出现的集合数
如何求解呢?
刚开始我是使用暴力的,因为我隐隐约约的感觉复杂度应该不算很高吧。。。
但是,我错了,这个复杂度是很高的,甚至可以达到O(n)级别。
而远非我们所想的O(logn)
那么我该怎么办呢?苦恼啊苦恼

看了题解。发现其实题解也是在找规律。这不过他是从公式中找规律。
他发现对于一个数x,假设是奇数。
那么根据函数,2x,2x+1 肯定出现他
4x,4x+1,4x+2,4x+3肯定出现他。
8x,8x+1,8x+2,8x+3,8x+4,8x+5,8x+6,8x+7肯定出现他
那么诸如此类。。。
我们发现了一个规律,就是2的倍数倍数的向上加。

但是,重要的时边界处理。

真是妙啊,好题,好思维。当时赛场能做出来也是真的思维灵活啊!!!!!!!!!!
脑在颤抖!!!!!!!!!!!

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
ll n,k;
ll check(ll mid){
    if (mid>n)return 0;
    ll ans = 0;ll dig = 2;
    if (mid&1){
        mid<<=1;
        ans++;
    }
    if (mid>n)return ans;
    while (mid+dig-1<=n){
        ans+=dig;
        mid<<=1;
        dig<<=1;
    }
    if (n-mid+1>0)ans+=n-mid+1;
    return ans;
}
ll Solve(){
    ll lft = 1,rgt = n/2;
    if (check(2)<k)return -1;
    ll ans = 0;
    while (lft<=rgt){
        ll mid = (lft+rgt)>>1;
        if (check(mid<<1)>=k){
            ans = max(ans,mid<<1);
            lft = mid+1;
        }
        else rgt = mid-1;
    }return ans;
}

ll Solve2(){
    ll lft = 0;ll rgt;
    if (n&1)rgt=n/2;
    else rgt = n/2 - 1;
    ll ans = 0;
    while (lft<=rgt){;
        ll mid = (lft+rgt)>>1;
        if (check(mid<<1|1)>=k){
            ans = max(ans,mid<<1|1);
            lft=mid+1;
        }
        else rgt = mid-1;
    }return ans;
}

int main(){
    cin>>n>>k;
    cout<<max(Solve2(),Solve())<<endl;
}