Codeforces Round #608 (Div. 2) E - Common Number (二分 思维 树结构)

🥟 🥟 🥟
题意:
在这里插入图片描述

首先我们可以按照题意把 1 ~ n 的路径画一下,比如这里取 n = 14 ,就可以得到下面这个可爱的树🌲

丑就丑吧实在没办法WA

从这个树可以得出几个结论:

1.数值x在1~n中出现的次数等于以他为根节点的树的大小

2.子树大小分奇偶有序,如:1 > 3 > 5 > 7,但 3与4大小不确定,所以必须分奇偶二分;

3.为了方便计算某节点为根的子树大小,我们规定奇数为左子树,偶数为右子树,由图可以看出一个树可以分成若干条链,链与链之间是(l×2,r×2+1)的关系,例如以2为根节点,可以分成【2,3】--->【4,7】--->【8,14】(这里应该是【8,15】但是n限制在了14),奇数为根节点类似。
代码如下:

ll n,k;
bool ok(ll x)
{
    queue<pair<ll,ll>>q;
    if(x&1) q.push(make_pair(x,x));
    else q.push(make_pair(x,x+1));
    ll ans=0;
    while(q.size())
    {
        auto it=q.front();q.pop();
        ans+=min(n,it.second)-it.first+1;
        if((it.first<<1)<=n) q.push(make_pair(it.first<<1,it.second<<1|1));
    }
    return ans>=k;
}
int main()
{
    cin>>n>>k;
    ll ans=0;
    {
        ll l=0,r=n/2,res=0;
        while(l<=r)
        {
            ll mid=(l+r)>>1;
            if(ok(mid<<1|1)) l=mid+1,res=mid<<1|1;
            else r=mid-1;
        }
        ans=max(ans,res);
    }
    {
        ll l=1, r=n/2, res=0;
        while(l<=r) 
        {
            ll mid = (l+r)>>1;
            if(ok(mid<<1))  l = mid+1, res=mid<<1;
            else    r = mid-1;
        }
        ans = max(ans, res);
    }
    cout<<ans<<endl;
    //stop;
    return 0;
}
posted @ 2019-12-23 11:12  Herlo  阅读(430)  评论(3编辑  收藏  举报