Bit Manipulation
Binary Search
Dynamic Programming
Description
You are given an integer k
and an integer x
. The price of a number num
is calculated by the count of set bits at positions x
, 2x
, 3x
, etc., in its binary representation, starting from the least significant bit. The following table contains examples of how price is calculated.
x
num
Binary Representation
Price
1
13
0 0 0 0 0 1 1 0 1
3
2
13
00 00 01 10 1
1
2
233
01 11 01 00 1
3
3
13
0 000 011 01
1
3
362
1 011 010 10
2
The accumulated price of num
is the total price of numbers from 1
to num
. num
is considered cheap if its accumulated price is less than or equal to k
.
Return the greatest cheap number.
Example 1:
Input: k = 9, x = 1
Output: 6
Explanation:
As shown in the table below, 6
is the greatest cheap number.
x
num
Binary Representation
Price
Accumulated Price
1
1
0 0 1
1
1
1
2
0 1 0
1
2
1
3
0 1 1
2
4
1
4
1 0 0
1
5
1
5
1 0 1
2
7
1
6
1 1 0
2
9
1
7
1 1 1
3
12
Example 2:
Input: k = 7, x = 2
Output: 9
Explanation:
As shown in the table below, 9
is the greatest cheap number.
x
num
Binary Representation
Price
Accumulated Price
2
1
0 00 1
0
0
2
2
0 01 0
1
1
2
3
0 01 1
1
2
2
4
0 10 0
0
2
2
5
0 10 1
0
2
2
6
0 11 0
1
3
2
7
0 11 1
1
4
2
8
1 00 0
1
5
2
9
1 00 1
1
6
2
10
1 01 0
2
8
Constraints:
1 <= k <= 1015
1 <= x <= 8
Solutions
Solution 1
Python3 Java C++ Go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 class Solution :
def findMaximumNumber ( self , k : int , x : int ) -> int :
@cache
def dfs ( pos , limit , cnt ):
if pos == 0 :
return cnt
ans = 0
up = ( self . num >> ( pos - 1 ) & 1 ) if limit else 1
for i in range ( up + 1 ):
ans += dfs ( pos - 1 , limit and i == up , cnt + ( i == 1 and pos % x == 0 ))
return ans
l , r = 1 , 10 ** 18
while l < r :
mid = ( l + r + 1 ) >> 1
self . num = mid
v = dfs ( mid . bit_length (), True , 0 )
dfs . cache_clear ()
if v <= k :
l = mid
else :
r = mid - 1
return l
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 class Solution {
private int x ;
private long num ;
private Long [][] f ;
public long findMaximumNumber ( long k , int x ) {
this . x = x ;
long l = 1 , r = ( long ) 1e17 ;
while ( l < r ) {
long mid = ( l + r + 1 ) >>> 1 ;
num = mid ;
f = new Long [ 65 ][ 65 ] ;
int pos = 64 - Long . numberOfLeadingZeros ( mid );
if ( dfs ( pos , 0 , true ) <= k ) {
l = mid ;
} else {
r = mid - 1 ;
}
}
return l ;
}
private long dfs ( int pos , int cnt , boolean limit ) {
if ( pos == 0 ) {
return cnt ;
}
if ( ! limit && f [ pos ][ cnt ] != null ) {
return f [ pos ][ cnt ] ;
}
long ans = 0 ;
int up = limit ? ( int ) ( num >> ( pos - 1 ) & 1 ) : 1 ;
for ( int i = 0 ; i <= up ; ++ i ) {
ans += dfs ( pos - 1 , cnt + ( i == 1 && pos % x == 0 ? 1 : 0 ), limit && i == up );
}
if ( ! limit ) {
f [ pos ][ cnt ] = ans ;
}
return ans ;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 class Solution {
public :
long long findMaximumNumber ( long long k , int x ) {
using ll = long long ;
ll l = 1 , r = 1e17 ;
ll num = 0 ;
ll f [ 65 ][ 65 ];
function < ll ( int , int , bool ) > dfs = [ & ]( int pos , int cnt , bool limit ) -> ll {
if ( pos == 0 ) {
return cnt ;
}
if ( ! limit && f [ pos ][ cnt ] != -1 ) {
return f [ pos ][ cnt ];
}
int up = limit ? num >> ( pos - 1 ) & 1 : 1 ;
ll ans = 0 ;
for ( int i = 0 ; i <= up ; ++ i ) {
ans += dfs ( pos - 1 , cnt + ( i == 1 && pos % x == 0 ), limit && i == up );
}
if ( ! limit ) {
f [ pos ][ cnt ] = ans ;
}
return ans ;
};
while ( l < r ) {
ll mid = ( l + r + 1 ) >> 1 ;
num = mid ;
memset ( f , -1 , sizeof ( f ));
int pos = 64 - __builtin_clzll ( mid );
if ( dfs ( pos , 0 , true ) <= k ) {
l = mid ;
} else {
r = mid - 1 ;
}
}
return l ;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 func findMaximumNumber ( k int64 , x int ) int64 {
var l , r int64 = 1 , 1e17
var num int64
var f [ 65 ][ 65 ] int64
var dfs func ( pos , cnt int , limit bool ) int64
dfs = func ( pos , cnt int , limit bool ) int64 {
if pos == 0 {
return int64 ( cnt )
}
if ! limit && f [ pos ][ cnt ] != - 1 {
return f [ pos ][ cnt ]
}
var ans int64
up := 1
if limit {
up = int ( num >> ( pos - 1 ) & 1 )
}
for i := 0 ; i <= up ; i ++ {
v := cnt
if i == 1 && pos % x == 0 {
v ++
}
ans += dfs ( pos - 1 , v , limit && i == up )
}
if ! limit {
f [ pos ][ cnt ] = ans
}
return ans
}
for l < r {
mid := ( l + r + 1 ) >> 1
num = mid
m := bits . Len ( uint ( num ))
for i := range f {
for j := range f [ i ] {
f [ i ][ j ] = - 1
}
}
if dfs ( m , 0 , true ) <= k {
l = mid
} else {
r = mid - 1
}
}
return l
}
GitHub