20231003 T2 32分

发布时间 2023-11-17 13:00:54作者: wscqwq

Alice 正在玩一个翻转串的游戏。这个游戏有一个S 串一个T 串。两个串都是01 串。Alice
每次操作可以把S 串的一个子串翻转。例如”101100”, 她选择”011” 翻转后得到”111000”。
Alice 希望进行最少次的操作,使得操作后的S 串内不包含T 作为S 的子串,你能否帮
助Alice 计算一下,最少需要多少次的翻转操作才能满足条件?如果无论怎么操作都不能满足
条件,输出-1

输入有两行,第一行一个01 串,代表串S,第二行一个01 串,代表串T。

对所有测试点数据, 保证1 ≤ |S| ≤ 200000, 1 ≤ |T| ≤ 3

子任务编号分值T 串限制
1 4 |T| = 1
2 12 |T| = 2, T1 ̸= T2
3 16 |T| = 2
4 20 |T| = 3, T1 ̸= T3
5 20 |T| = 3, T1 ̸= T2
6 28 |T| = 3

我们考虑前三个子任务。

1:考虑直接判断即可。

2:考虑我们要将01分到一边。我们发现任意一个01至少需要一次操作(实际上操作时是找到01最左边的0,最右边的1整体操作),统计连续段个数即可。

3:考虑是00.发现如果0的个数>1的个数+1,那么肯定不可能(鸽巢原理)。否则,每次操作至多拆掉一个0,统计00个数即可;11同理,对称即可。


#include<bits/stdc++.h>
using namespace std;
const int N=200010;
int n,m;
char s[N],t[5];
int main(){
freopen("flip.in","r",stdin);
freopen("flip.out","w",stdout);
scanf("%s%s",s,t);
n=strlen(s),m=strlen(t);
bool no=0;
for(int i=0;i+m-1<n;++i){
bool ca=1;
for(int j=0;j<m;++j)
if(s[i+j]!=t[j]){
ca=0;
break;
}
no|=ca;
}
if(n<m||!no){
puts("0");
return 0;
}
if(m==1){
for(int i=0;i<n;++i)
if(s[i]==t[i]){
puts("-1");
return 0;
}
puts("0");
return 0;
}
if(m==2&&t[0]!=t[1]){
int ans=0;
for(int i=1;i<n;++i)
if(s[i]!=s[i-1]&&s[i]==t[1])++ans;
printf("%d",ans);
return 0;
}
if(m==2&&t[0]==t[1]){
int cnt0=0,cnt1=0,ans=0;
for(int i=0;i<n;++i)
if(s[i]=='1')++cnt1;
else ++cnt0;
if(t[0]=='1'&&cnt1>cnt0+1||t[0]=='0'&&cnt0>cnt1+1){
puts("-1");
return 0;
}
for(int i=0;i<n-1;++i)
if(t[0]=='0'&&s[i]=='0'&&s[i+1]=='0'||t[0]=='1'&&s[i]=='1'&&s[i+1]=='1')
++ans;
printf("%d",ans);
return 0;
}
puts("-1");
return 0;
}