E. Product of Closures
E. Product of Closures
设 \(C(x)\) 表示 \(x\) 的无前导零二进制表示重复无限次拼接,例如:\(C(4) = 10010010010010...\)。
给定 \(l, r, n\),求解 \(x\) 和 \(y\) (\(l \le x \lt y \le r\)),使得 \(C(x) \mathop{\&} C(y)\) 的二进制表示字典序最小,输出 \(C(x) \mathop{\&} C(y)\) 的前 \(n\) 二进制位。
多测,\(1 \le t,n \le 1000\), \(1 \le l \lt r \lt 2^{30}\)。
链接:CF2242E
设 \(kr = \lfloor \log_{2}{r} \rfloor\),\(kl = \lfloor \log_{2}{l} \rfloor\),以下长度均为二进制表示的长度。分三类讨论。
情况 1:\(kl = kr\)。最终的数是长度为 \(kr\) 的无限循环,我们尽量要使得二进制位不同,发现如果某一位 \(l_i \neq r_i\),那一定是 \(l_i = 0,r_i = 1\),我们就可以使 \(r_j(j > i)\) 为 \(0\),那么后面位置的答案就都是 \(0\) 了。
情况 2:\(kl + 1 = kr\)。最终的数是长度为 \(k = kl \times kr\) 的无限循环,由于 \(kl < kr\),那么 \(y\) 除了首位都可以是 \(0\),即 \(x = l,y = 2^{kr}\)。拼接求解即可。
情况 3:\(kl + 1 < kr\)。最终的数是长度为 \(k = \text{lcm}(kl,kr)\) 的无限循环,可以有 \(x = 2^{kr - 1},y = 2^{kr}\)。这样 \(k\) 最大,并且只有循环首位是 \(1\),拼接求解即可。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using i128 = __int128;
const double PI = acos(-1.0);
const int MOD = 1000000007; // 998244353
#define MAXN 100005
string trans(int x){
string res;
while(x > 0){
if(x & 1) res += "1";
else res += "0";
x >>= 1;
}
reverse(res.begin(), res.end());
return res;
}
int getLen(int x){
int res = 0;
while(x > 0){
res++;
x >>= 1;
}
return res;
}
void print(string s, int len){
int cnt = 1;
while(cnt <= len){
for(int i = 0;cnt <= len && i < s.length();cnt++, i++){
cout << s[i];
}
}
cout << "\n";
}
void solve(){
int l, r, n;
cin >> l >> r >> n;
int kr = getLen(r), kl = getLen(l);
if(kl == kr){
string L = trans(l), R = trans(r);
bool flag = false;
for(int i = 0;i < kl;i++){
if(L[i] != R[i]){
flag = true;
}
if(flag) L[i] = '0';
}
print(L, n);
}else if(kl + 1 == kr){
string L = trans(l), R = trans(r);
for(int i = 1;i < kr;i++) R[i] = '0';
string tL = L, tR = R;
int K = kr * kl;
for(int i = 1;i < kl;i++) R += tR;
for(int i = 1;i < kr;i++) L += tL;
for(int i = 0;i < K;i++){
if(L[i] != R[i]) L[i] = '0';
}
print(L, n);
}else{
int K = kr * (kr - 1);
string res = "1";
for(int i = 1;i < K;i++){
res += "0";
}
print(res, n);
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int T = 1;
cin >> T;
while(T--){
solve();
}
return 0;
}
做这题的时候想到寒假营的类似的题还没补,于是去补了 pwp。
AND vs MEX
给定 \(l, r\),初始有一个可重整数集合 \(\Bbb{S}\),可以进行任意次以下操作。
从区间 \([l, r]\) 中选择至少一个不同的整数,将这些整数的 \(\text{AND}\) 加入集合 \(\Bbb{S}\) 中。
请最大化 \(\Bbb{S}\) 的 \(\text{MEX}\)。
多测,\(0 \leq l \leq r < 2^{30}\)。
设 \(kr = \lfloor \log_{2}{r} \rfloor\),\(kl = \lfloor \log_{2}{l} \rfloor\),以下长度均为二进制表示的长度。分三类讨论。
特判:\(l = 0\) 时可以取到 \([0, r]\) 所有数字,答案为 \(r + 1\)。
情况 1:\(kl = kr\)。最高位相同,发现无法得到 \(0\),所以答案为 \(0\)。
情况 2:\(kl + 1 = kr\)。取 \(L\) 为 \(2^{kl} - 1\),即全 \(1\),\(R\) 为 \([2^{kr-1},r-2^{kr-1}] = [2^{kl},r-2^{kl}]\),可以得到 \([0, r - 2^{kl}]\)。考虑 \((r - 2^{kl}, l)\) 的范围能否取到,设 \(l = 1101100\),可以取 \(x = 1101111,y = [1110000,1111111]\),做与运算,得到 \([1100000, L]\),这样就能得到 \(L\) 的下限位,然后交起来就可以了。
情况 3:\(kl + 1 < kr\)。取 \(L\) 为 \([2^{kl + 1},2^{kl} - 1]\),\(R\) 为 \(2 ^ {kr}\)。这样可以得到 \([0, 2^{kl + 1} - 1]\),由于 \(2^{kl + 1} - 1 \ge l\),所以最终可以取得 \([0,r]\),答案为 \(r + 1\)。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using i128 = __int128;
const double PI = acos(-1.0);
const int MOD = 1000000007; // 998244353
#define MAXN 100005
int getLen(int x){
int res = 0;
while(x > 0){
res++;
x >>= 1;
}
return res;
}
void solve(){
int l, r;
cin >> l >> r;
int kr = getLen(r), kl = getLen(l);
if(l == 0){
cout << r + 1 << "\n";
}else if(kl == kr){
cout << "0\n";
}else if(kl + 1 == kr){
int now1 = r - (1 << (kr - 1)) + 1;
int now2 = 0;
for(int i = kl - 1;i >= 0;i--){
if(((l >> i) & 1)){
now2 += (1 << i);
}else{
break;
}
}
if(now2 <= now1) cout << r + 1 << "\n";
else cout << now1 << "\n";
}else{
cout << r + 1 << "\n";
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int T = 1;
cin >> T;
while(T--){
solve();
}
return 0;
}
浙公网安备 33010602011771号