Codeforces Round #608 (Div. 2) E - Common Number (二分 思维 树结构)
🥟 🥟 🥟
题意:
首先我们可以按照题意把 1 ~ n 的路径画一下,比如这里取 n = 14 ,就可以得到下面这个可爱的树🌲
从这个树可以得出几个结论:
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;
}