D. Problem with Random Tests

D. Problem with Random Tests

You are given a string $s$ consisting of $n$ characters. Each character of $s$ is either $0$ or $1$.

A substring of $s$ is a contiguous subsequence of its characters.

You have to choose two substrings of $s$ (possibly intersecting, possibly the same, possibly non-intersecting — just any two substrings). After choosing them, you calculate the value of the chosen pair of substrings as follows:

let $s_1$ be the first substring, $s_2$ be the second chosen substring, and $f(s_i)$ be the integer such that $s_i$ is its binary representation (for example, if $s_i$ is $\text{11010}$, $f(s_i)=26$);
the value is the bitwise OR of $f(s_1)$ and $f(s_2)$.
Calculate the maximum possible value you can get, and print it in binary representation without leading zeroes.

Input

The first line contains one integer $n$ — the number of characters in $s$.

The second line contains $s$ itself, consisting of exactly $n$ characters $0$ and/or $1$.

All non-example tests in this problem are generated randomly: every character of $s$ is chosen independently of other characters; for each character, the probability of it being $1$ is exactly $\frac{1}{2}$.

This problem has exactly $40$ tests. Tests from $1$ to $3$ are the examples; tests from $4$ to $40$ are generated randomly. In tests from $4$ to $10$, $n=5$; in tests from $11$ to $20$, $n=1000$; in tests from $21$ to $40$, $n={10}^{6}$.

Hacks are forbidden in this problem.

Output

Print the maximum possible value you can get in binary representation without leading zeroes.

Examples

input

5
11010

output

11111

input

7
1110010

output

1111110

input

4
0000

output

0

 

解题思路

  这题一直看错题,硬是把或看成异或,当时模拟样例的时候还一直出错,还以为是样例给错了,然后拿样例去问同学,结果人家题都没看就问我是不是按位或,当时心态直接炸了。

  首先对于最优解,这两个子串中必然有一个子串是取整个字符串$s$。这是因为这个是按位或运算,位数越多得到的结果只可能变大而不会减小。考虑此时两个子串中不存在一个子串取整个$s$,那么我们选择其中一个子串,将其变成字符串$s$,那么得到的结果不会变得糟糕(因为位数增加)。

  同时也可以发现另外一个子串前缀扩展到$s$的第一个字符$s[1]$结果也不会变差。

  那么现在一个子串已经确定了(取整个字符串$s$),接下来考虑另外一个字符串。

  对于字符串$s$我们从左往右找到第一个$1$出现的位置$p_1$,那么$s[1 \sim p_1]$内都是都是$0$,可以发现此时无论另外一个子串怎么取,都不可以将答案的$[1, p_1]$这个区间的任意一个位置置成$1$,因此答案最大是$[p_1, n]$这个区间内全为$1$。这时再从$p_1$这个位置开始往右找到第一个$0$的位置$p_2$,那么$s[p_1 \sim p_2 - 1]$内都是$1$。很明显我们要在另外一个子串的$p_2$位置取$1$,才能取到尽可能大的结果,而这个$1$就要在区间$[p_1, p_2 - 1]$内取(如果在$p_2$往后取的话,由于位数不足,因此另外一个子串的$p_2$位置必然是$0$)。那么我们就枚举区间$[p_1, p_2 - 1]$的每一个$1$,把这个$1$放到子串$p_2$这个位置,即这个子串就是$s[i \sim i + n - p_2] \, (p_1 \leq i \leq p_2 - 1)$。前面我们有说这个子串扩展到前缀结果不会变差,可以发现由于此时前缀是 0 0 ... 1 1 1 这个形式,结果也不会比$[p_1, n]$这个区间内全为$1$的更优,因此在这里是否扩展到前缀对结果没有影响,因此可以不用扩展到前缀。

  然后是时间复杂度的问题,假设第一段连续的$1$的长度为$m$,那么时间复杂度就是$O(m \cdot n)$,但这题的数据是随机的,$0$和$1$出现的概率均为$\frac{1}{2}$,因此如果$m$要取到$20$,即第一段有$20$个连续的$1$,这个概率大概是${10}^{-6}$这个量级,即非常的低,因此我们可以认为$m$是一个比较小的常数,因此时间复杂度可以期望估计为$O(n)$。

  AC代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 int main() {
 5     int n;
 6     string s;
 7     cin >> n >> s;
 8     
 9     int p1 = s.find('1');
10     if (p1 == -1) {
11         cout << '0';
12         return 0;
13     }
14     
15     int p2 = s.find('0', p1);
16     string ret = s;
17     for (int i = p1; i < p2; i++) {
18         string t = s;
19         for (int j = i + n - 1 - p2, k = n - 1; j >= i; j--, k--) {
20             t[k] |= s[j];
21         }
22         ret = max(ret, t);
23     }
24     cout << ret.substr(ret.find('1'));
25     
26     return 0;
27 }

 

参考资料

  Educational Codeforces Round 137 Editorial:https://codeforces.com/blog/entry/108153

posted @ 2022-10-22 10:19  onlyblues  阅读(94)  评论(1编辑  收藏  举报
Web Analytics