cf1271E.Common Number

Link

Link

Solution

看到这个题肯定是去想二分,先不管这东西是不是满足单调性,我们无论如何要解决的一个问题就是:

给定一个 x x ,如何判断这个东西在多少个 p a t h ( i ) path(i) 中出现过?

一开始我想到数位 d p dp 的那种方法上去了,结果 c h e c k check 函数写的很麻烦,算的还不对

其实直接按照给的这个式子来就好

对于一个奇数 x x ,首先 p a t h ( x ) path(x) 中肯定出现了这个数字,再者 p a t h ( 2 x ) , p a t h ( 2 x + 1 ) path(2x),path(2x+1) ,然后是 p a t h ( 4 x ) , p a t h ( 4 x + 1 ) , p a t h ( 4 x + 2 ) , p a t h ( 4 x + 3 ) path(4x),path(4x+1),path(4x+2),path(4x+3) ,按照这个规律下去。统计这个东西显然只需要一个 l o g log

偶数的时候大同小异,先是 p a t h ( x ) , p a t h ( x + 1 ) path(x),path(x+1) ,然后 p a t h ( 2 x ) , p a t h ( 2 x + 1 ) , p a t h ( 2 x + 2 ) , p a t h ( 2 x + 3 ) path(2x),path(2x+1),path(2x+2),path(2x+3) ,依此类推

可以发现偶数和奇数虽然计算方式不同,但是他们各自的结算结果都是随着 x x 的增大而减小的

所以只需要奇数偶数分别二分最后再取 m a x max 即可

Code

n, k = [int(x) for x in input().split()]

def chg(n):
    lis = []
    for i in range(100):
        if 2**i>n:
            break
        lis.append( ( n & (2**i) ) >> i )
    return lis

def calc(x):
    cnt = 0
    k = 1
    if x%2==0:
        x=x//2
        cnt = -1
    while k*x <= n:
        cnt += min(k*x+k-1,n) - k*x + 1
        k *= 2
    return cnt

l=1
r=n
while l<r:
    mid = l+r+1>>1
    if calc(2*mid-1) >= k: l=mid
    else: r=mid-1
ans = 2*l-1

l=1
r=n
while l<r:
    mid = l+r+1>>1
    if calc(2*mid) >= k: l=mid
    else: r=mid-1
if calc(2*l) >= k:
    ans = max(ans,2*l)

print(ans)
发布了948 篇原创文章 · 获赞 77 · 访问量 21万+

猜你喜欢

转载自blog.csdn.net/FSAHFGSADHSAKNDAS/article/details/104543584