Description
小C有n个区间,其中第i个区间为[li,ri],小C想从每个区间中各选出一个整数,使得所有选出的数and起来得到的结果最大,请你求出这个值。
Input Format
第一行一个正整数n,表示区间个数。接下来n行,每行两个非负整数li,ri。
(n leq 10^5, li leq ri leq 10^{18})
Output Format
输出一个整数,表示答案。
Solution
跟二进制有关,那么一般都要转化成二进制下操作,
我们发现,最后的答案其实是可以看成(2^{k_1}+2^{k_2}+...2^{k_n}),
那么其实就是选出来的数列化成二进制后第(k_1,k_2...k_n)位都为1,
而(k_i)越大就越优,那么就有了思路,按二进制为从高到低验证,
如果第(i) 位符合条件,那么(Ans+=2^i) ,答案就算出来了,
当符合条件的时候,需要特殊处理否则会影响到后面的判断,
只要把所有区间都往左移动(2^i)即可,即减去(2^i),
Code
#include <cstdio>
#include <algorithm>
#define LL long long
#define N 100010
using namespace std;
int n;
LL Ans, l[N], r[N];
inline LL read() {
LL x = 0, r = 1; char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-')r = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
return x * r;
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
l[i] = read(), r[i] = read();
for (int k = 62; k >= 0; k--) {
LL pk = 1ll * 1 << k;
bool flag = 1;
for (int i = 1; i <= n; ++i)
if (r[i] < pk) flag = 0;
if (flag) Ans += pk;
for (int i = 1; i <= n; ++i) {
if (flag || l[i] >= pk) l[i] -= pk, r[i] -= pk;
}
}
printf("%lld
", Ans);
return 0;
}