题目笔记——P10069 [CCO 2023] Flip it and Stick it
赛后发现错因竟是 -1 写成 1,1 和 0 写反,+= 写成 =。
题意
判断能否将一个字符串S通过任意次翻转子串后使得 \(S\) 不包含 \(T\) 的长度很小作为子串,如果可以,。
仔细观察可以发现 \(T\) 的长度很小,最多只有3个单位长度,反正不会做,来分类讨论一下吧。
\(|T|=1\)
\(S\) 字符串只会被旋转,其中的字符不会改变,如果一开始 \(S\) 中就有 \(T\) 了,那么 \(T\) 就永远是 \(S\) 的子串,输出 -1,否则一开始 \(S\) 就不包含 \(T\) 作为子串,输出 0。
\(|T|=2\)
\(T_{1}\neq T_{2}\)
如果 \(T_{1}\neq T_{2}\)(\(T_{1}\) 指 \(T\) 的第 \(1\) 位),就要保证在 \(S\) 中 \(T_{1}\) 后面没有任何 \(T_{2}\)、\(T_{2}\) 前面没有任何 \(T_{1}\),就是要使 \(S\) 变成一段 \(T_{2}\) 加一段 \(T_{1}\),每一次翻转可以使一个前面有 \(T_{1}\) 的 \(T_{2}\) 翻转到最前面,所以就是找 \(S\) 中 \(T\) 的个数。
\(T_{1}=T_{2}\)
如果 \(T_{1}=T_{2}\),就要保证在 \(S\) 中每个 \(T_{1}\) 之间都有至少一个另一个数间隔,所以就要先判断 \(S\) 中 \(1\) 和 \(0\) 的个数,如果 \(S\) 中 \(T_{1}\) 的个数大于另一个数的个数加一,每一次翻转可以使一个 \(T\) 之间加一个数,所以就是找 \(S\) 中 \(T\) 的个数。
\(|T|=3\)
\(T_{1}\neq T_{3}\)
我们发现每一次翻转可以消除 \(S\) 中的一个 \(T\),类似上面的\(|T|=2,T_{1}\neq T_{2}\)。
\(T=010\) 或 \(T=101\)
我们发现此时 \(T\) 翻转不会改变,且一次可以消除 \(S\) 中的两个 \(T\),所以答案就是 \(\lceil\frac{num_T}{2}\rceil\),其中 \(num_T\) 是指 \(S\) 中 \(T\) 的个数。
\(T=000\) 或 \(T=111\)
类似于 \(|T|=2,T_{1}=T_{2}\),\(S\) 中的每个 \(T\) 都要被分隔开,且一次只能消除一次,我们可以看每一个 \(T_{1}\oplus1\)(即 \(T_{1}\) 取反)左右 \(T_{1}\) 连续的个数,对于每个连续个数大于 \(2\) 的连续段中如果有可以一次性移走两个的连续段,可以优先选择将其移至相邻 \(T_{1}\oplus1\) 之间没有 \(T_{1}\) 的段。
代码(码风过史,勿喷)
#include <bits/stdc++.h>
using namespace std;
#define int long long
int num, num1, num0, cnt1, cnt2, wt1, wt2;
string s, t;
vector <int> e;
signed main(){
cin >> s >> t;
if(s.find(t) >= s.size()){
cout << 0;
return 0;
}
if(t.size() == 1){
cout << -1;
return 0;
}
if(t.size() == 2){
if(t[0] != t[1]){
for(int i = 1; i < s.size(); i++){
if(s[i - 1] == t[0] && s[i] == t[1]) num ++;
}
cout << num;
return 0;
}
if(t == "00"){
for(int i = 0; i < s.size(); i++){
if(s[i] == '1') num1 ++;
else num0 ++;
}
if(num1 < num0 - 1){
cout << -1;
return 0;
}
for(int i = 1; i < s.size(); i++){
if(s[i - 1] == '0' && s[i] == '0') num ++;
}
cout << num;
return 0;
}
if(t == "11"){
for(int i = 0; i < s.size(); i++){
if(s[i] == '1') num1 ++;
else num0 ++;
}
if(num0 < num1 - 1){
cout << -1;
return 0;
}
for(int i = 1; i < s.size(); i++){
if(s[i - 1] == '1' && s[i] == '1') num ++;
}
cout << num;
return 0;
}
return 0;
}
if(t[0] != t[2]){
for(int i = 2; i < s.size(); i++){
if(s[i - 2] == t[0] && s[i - 1] == t[1] && s[i] == t[2]) num ++;
}
cout << num;
return 0;
}
if(t == "000"){
for(int i = 0; i < s.size(); i++){
if(s[i] == '1'){
e.push_back(num);
num = 0;
num1 ++;
}
else{
num ++;
num0 ++;
}
}
e.push_back(num);
if(2 * (num1 + 1) < num0){
cout << -1;
return 0;
}
cnt1 = 0, cnt2 = 0, wt1 = 0, wt2 = 0;
for(int i : e){
if(i == 0) cnt2 ++;
if(i == 1) cnt1 ++;
if(i > 2){
wt2 += (i - 2) / 2;
wt1 += i % 2;
}
}
if(wt2 <= cnt2) cout << wt1 + wt2;
else cout << wt1 + cnt2 + (wt2 - cnt2 << 1);
return 0;
}
if(t == "111"){
for(int i = 0; i < s.size(); i++){
if(s[i] == '1'){
num ++;
num1 ++;
}
else{
e.push_back(num);
num = 0;
num0 ++;
}
}
e.push_back(num);
if(2 * (num0 + 1) < num1){
cout << -1;
return 0;
}
cnt1 = 0, cnt2 = 0, wt1 = 0, wt2 = 0;
for(int i : e){
if(i == 0) cnt2 ++;
if(i == 1) cnt1 ++;
if(i > 2){
wt2 += (i - 2) / 2;
wt1 += i % 2;
}
}
if(wt2 <= cnt2) cout << wt1 + wt2;
else cout << wt1 + cnt2 + (wt2 - cnt2 << 1);
return 0;
}
for(int i = 2; i < s.size(); i++){
if(s[i - 2] == t[0] && s[i - 1] == t[1] && s[i] == t[2]) num ++;
}
cout << (num + 1) / 2;
return 0;
}

浙公网安备 33010602011771号