·题意
给定n颗糖果,要求分成m份,每份c_i (c_i >= 1)个, 求c_1 & c_2 & c_3 & ... & c_m 的最大值。
·分析
·首先我们知道,根据位与&的特性,就算有某些c_i 占据了高的数位,有一个c_j 在该位上为0,那&起来的结果肯定为0。
·所以我们希望位与和的结果足够大,就得保证每个c_i 的最高位都为1。
·这启发我们从高位到低位枚举贪心,看看n 能分成m个的哪些位。
·枚举位
·若我们用的还剩下tmp个糖果, 当前为从高(31)到低(0) 第i位,如果最后的结果该位为1,则需要 m * (1 << i) 个糖果;
·若 tmp >= m * (1 << i), 则直接选该位,tmp 对应减去m * (1 << i)
·若 tmp < m * (1 << i), 注意,因为tmp 有可能比剩下的位全是1时还大( 即大于 m * ((1 << i) - 1)), 此时,我们需要将多出来的糖果放在这一位, 因为tmp < m * (1 << i) 所以这一位肯定填不满,不用选择该位;
for (int i = 31; i >= 0; i -- )
{
ll bit = (1ll << i); // (对应盖位的二进制数)
if (tmp >= bit * m) // tmp >= m * (1 << i)
{
tmp -= bit * m;
ans |= bit;
}
else if (tmp > bit * m - m) // tmp > m * ((1 << i) - 1)
{
tmp -= (tmp - bit * m + m + bit - 1) / bit * bit; // (减去能放在该位的多余糖果,注意是上取整)
}
}
·复杂度
时间复杂度 O(32 * T) 即 O(T);
空间负责度 O(1)
·完整代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
ll n, m;
int main()
{
int T;
scanf("%d", &T);
while (T -- )
{
scanf("%lld%lld", &n, &m);
ll tmp = n, ans = 0;
for (int i = 31; i >= 0; i -- )
{
ll bit = (1ll << i);
if (tmp >= bit * m)
{
tmp -= bit * m;
ans |= bit;
}
else if (tmp > bit * m - m)
{
tmp -= (tmp - bit * m + m + bit - 1) / bit * bit;
}
}
printf("%lld\n", ans);
}
return 0;
}
希望对大家有所帮助qwq
还有,各位除夕快乐!

京公网安备 11010502036488号