Post

题解 - Qingshan Loves Strings 2

算法竞赛题解 | 难度:普及

题目链接 - CF1890C题目链接 - CF1889A (洛谷)

题意描述

我们称长度为 $k$ 的01串 $a$ 是好的且仅当

  • $\forall i \in \left [ 1,k \right ], ai \ne a{k-i+1}$

比如,$\texttt{10}$ , $\texttt{1010}$ , $\texttt{111000}$ 是好的,而 $\texttt{11}$ , $\texttt{101}$ , $\texttt{001}$ , $\texttt{001100}$ 不是好的。

现在给你一个01串 $s$,你可以执行不多于 $300$ 次以下操作使得 $s$ 变为好的(次数可以为 $0$):

  • 插入 $\texttt{01}$到 $s$的任意位置

请你判断是否有解,并在有解的情况下输出操作次数和每个操作的插入位置。

输出格式

对于每组数据,如果无法使 $s$ 变好,输出一行一个 $-1$。

否则,输出 $p$ ( $0 \le p \le 300$ ) 表示操作总数。

接下来,输出 $p$ 个整数 $x_i$ ( $0 \le x_i \le n+2i-2$ ) 表示操作位置。当 $x_i = 0$ 时表示插入$\texttt{01}$到 $s$ 开头,否则表示插入到 $s$ 的第 $x_i$ 项后面。

可以证明,在此问题的约束下,如果有答案存在,那么总有一个答案仅需要 $300$ 次以下的操作数便可以完成。

样例 #1
样例输入 #1
1
2
3
4
5
6
7
8
9
10
11
12
13
6
2
01
3
000
4
1111
6
001110
10
0111001100
3
001
样例输出 #1
1
2
3
4
5
6
7
8
9
0

-1
-1
2
6 7
1
10
-1
前置条件

如果这个字符串是对称的,那么$\texttt{0}$和$\texttt{1}$的数量应是一样的。从这里可以直接判断答案是否存在。

做法一

赛场上想到的做法 我们将串中的所有$\texttt{01}$都去除,最后剩下若干$\texttt{10}$,且只可能有一种放法。 往这些$\texttt{10}$中插入$\texttt{01}$,只要保证插入的顺序是对称的,序列就是好的。

做法二

订正做法 思路或许是差不多的,但是明显这个方法实现更快更好。 建立头指针、尾指针,如果头尾不同,可以忽略这对,如果头尾相同且为$\texttt{0}$,在尾处加上$\texttt{01}$,如果头尾相同且为$\texttt{1}$,在头处加上$\texttt{01}$,头指针递增,尾指针递减。

分析

检测到的$\texttt{0}$和$\texttt{1}$有一个是$\texttt{10}$中的,手模一下样例,就会发现需要添加$\texttt{01}$了。 对于算法,实际上等价于将最后的$\texttt{1}$移到最前面,或将最前面的$\texttt{0}$移到最后面。

代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include<bits>
using namespace std;
typedef long long ll;
#define maxd(x, y) ((x) > (y) ? (x) : (y))
#define mind(x, y) ((x) < (y) ? (x) : (y))
int T;
const int MAXN = 2e5 + 10;
int n;
string s;
int main()
{
  // freopen(C.in, r, stdin);
  scanf(%d, &T);
  while(T--) {
    scanf(%d, &n);
    cin >> s;
    int flag = 1;
    //判断-1
    int cnt0 = 0, cnt1 = 0;
    for(int i = 0; i < n; i++) {
      if(s[i] == '0') cnt0++;
      else cnt1++;
    }
    if(cnt0 != cnt1) {
      printf(-1\n);
      continue;
    }
    //计算正常情况
    vector<int> ans;
    int i = 0, j = n - 1;
    while(i <= j) {
      if(s[i] != s[j]) {
        s.pop_back();
        i++, j--;
      } else if(s[i] == '0') {
        s += 01;
        ans.emplace_back(j + 1);
        j += 2;
      } else if(s[i] == '1') {
        s.insert(s.begin() + i, '1');
        s.insert(s.begin() + i, '0');
        ans.emplace_back(i);
        j += 2;
      }
    }
    printf(%d\n, ans.size());
    for(auto i : ans) printf(%d , i);
    printf(\n);
  } 
  return 0;
}</int></bits>
This post is licensed under CC BY 4.0 by the author.