Educational Codeforces Round 137 (Div. 2)D. Problem with Random Tes(暴力+bitset)

73 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第18天,点击查看活动详情
本文已参与「新人创作礼」活动,一 起开启掘金创作之路。

题目

image.png 中文大意

给我们一个只由010和1构成的字符串然后我们从里面选择两个区间作为字符串s1,s2s1,s2并且区间是可以覆盖和重复的计算最大s1s2s1|s2输出答案的时候不用输出前导零

解法

对于题目给出的样例[11010][11010],我们知道位运算中或运算后的值是肯定大于等于它本身的所以我们第一个模板串我们就选择它本。 这样我们就有了一个s1=11010,现在我们就是要找出一个s2去与这个s1进行或运算操作。我们发现在s1中前面连续的1是不用进行位运算的因为它们无论怎么操作最后得出的结果都是他们本身的值。所以对于s1我们需要进行位运算的部分就是在我们将s1去除前导零过后第一个连续1之后的部分。所以我们只需要在原字符串截取相同长度的字符串进行位运算即可

tips

我们发现题目给的字符串长度到达了1e61e6如果我们用二进制去保存每一位的1的话是不可能的所以c++库中给出了一个容器 bitsetbitset 可以很好的去处理这种状况它的初始化可以直接传递字符串进去但是传递的字符串的每一位值都必须是0/1不然就会报错也可以直接传递一个数字(如果是字符串的话它在bitset里面是倒着存的如果我们需要的话是要反向遍历的)

Code

const int N = 1e6 + 10;//题目给出的最大字符串长度
void solve()
{
   int n; cin >> n;
   string s; cin >> s;
   if(count(all(s),'0') == n) { //如果全为0直接输出0即可
     cout << 0 << endl;
     return;
   }
   s = s.substr(s.find('1'));//从字符串中第一个1开始截取字符串(去除前导零)
   n = s.size();
   bitset<N> res(s),a(s); // 初始化N是bitset的最大长度
   int len = 0;
   for(int i = 0; i < s.size(); i++){ //找出字符串中我们需要去进行位运算的长度
        if(s[i] == '0') {
            len = s.size() - i;
            break;
        }
   }
   for(int i = 0; i + len - 1 < s.size(); i++) { // 按位枚举
       string x = s.substr(i,len);
       bitset<N> b(x);
       bitset<N> t = (a|b);
       for(int i = n - 1; i >= 0; i--) {
         if(res[i] > t[i]) break;
         if(t[i] > res[i]) {
            res = t; break;
         }
       }
   }
   for(int i = n-1; i >= 0; i--) cout << res[i];//倒着输出即可
   cout << endl;
}