题解/算法 {3007. 价值和小于等于 K 的最大数字}
@LINK: https://leetcode.cn/problems/maximum-number-that-sum-of-the-prices-is-less-than-or-equal-to-k/description/
参见@LINK: (https://editor.csdn.net/md/?articleId=130768151)-(@LOC_0)
;
遍历所有数位这是个算法模板(即数位DP所使用的核心算法), 遍历[0...R]
的所有数的数位, 即遍历R
的所有数位 对于[pre i ?]
其中pre,i
是确定的 而?
里面 他的每个数位里 {0,1}
出现的次数是相同的 都是tot/2
个(tot
是该子集的大小), 因此可以计算出每个非特殊子集里面1
的个数;
但是问题在于 *特殊子集0?
*是不满足这个性质的, 因为要去掉前导零 即根据上面的性质 {0,1}
都是有tot/2
个 但是0
的个数是错误的, 但是这个性质仍然可用! 因为题目不会涉及到0
我们求的是1
因此依然可行;
long long findMaximumNumber(long long K, int X) {
auto check = [&]( int64_t _mid)->bool{
auto vec = Integer::IntegerToVector( _mid, -1, 2);
std::reverse( vec.begin(), vec.end()); // 让`vec`的低位是数字低位;
auto kk = K;
FOR_( i, 1, vec.size()){
if( (i%X==0) && (vec[i-1]==1)){ -- kk; if(kk<0){ return 0;}}
}
FOR_( i, 1, vec.size()){
if( vec[i-1] == 1){ // 枚举让该位放`0`, 即所有形如`[pre 0 ?]`的数;
auto tot = (1LL << (i-1));
FOR_( j, 1, vec.size()){
if( j < i){
if( j%X == 0){ kk -= (tot / 2); if(kk<0){ return 0;}}
}
else if( j > i){
if( (j%X==0) && (vec[j-1]==1)){ kk -= (tot); if(kk<0){ return 0;}}
}
}
}
}
if(kk<0){ return 0;}
return 1;
};
int64_t l = 0, r = 4e18;
while( l < r){
auto mid = (l+r+1)>>1;
if( check( mid)){ l = mid;}
else{ r = mid - 1;}
}
ASSERT_( check(r));
return r;
}