题解:P10069 [CCO2023] Flip it and Stick it

· · 题解

题意简述

给定仅由 01 构成的字符串 ST,你可以翻转 S 的子串,使得其子串中不包含 T,求最小操作次数,若无解输出 -1

做法分析

一点思路没有,看数据范围。

发现 \left |T\right | 很小,并且部分分内贴心的给出了特殊的 T。考虑分类讨论。显然我们并不在意哪个是 0 哪个是 1,只关心他们的相对位置。

\left |T\right |=l

显然看是否存在 T,存在即无解,否则输出 0

形如 10,我们发现最终结果一定可以形如 000\dots0111,一次翻转可以将一个 1 翻转到后方,答案即为 01 串的个数。

形如 11,我们发现最终结果一定形如 1010\dots1000,对于任意两对 11,可以通过一次翻转操作拆散。但如果 1 的数量过半,则一定无解。答案即为 11 串的个数除以二上取整。

发现这类似于 11,答案就是出现次数除以二上取整。

同样,类似于 10,答案即为出现次数。

发现它也具有不对称的特点,同上,答案即为出现次数。

这位更是重量级。

我们发现,问题能够转化为让 S 中不存在连续的三个 1。即通过翻转让 1 翻到 0 的中间去。为了不让 1 与其它的 1 接上,只有 11 中间或者 101 中间可以容纳 1

那就统计之后再讨论就好了。如果两种操作都不剩了,那就是无解。 细节看代码。 ``` #include<bits/stdc++.h> #define AC return 0; #define pr(n) printf("%d",(n)) #define hh puts("") #define kg printf(" ") using namespace std; namespace fr{ int read() { int x=0,flag=1; char ch=getchar(); for(;ch>'9'||ch<'0';ch=getchar())if(ch=='-')flag=-1; for(;ch<='9'&&ch>='0';ch=getchar())x=(x<<3)+(x<<1)+ch-'0'; return flag*x; } } using namespace fr; string s,t; bool cmp(int a,int b){return a>b;} void sol1()//1 { char a=t[0]; for(auto i:s)if(i==a){puts("-1");return ;} puts("0"); } void sol2()//10 { int res=0; for(int i=0;i<s.size()-1;++i) { if(s.substr(i,2)==t)++res; } pr(res); } void sol3()//11 { char a=t[0]; int cnt=0,res=0; for(int i=0;i<s.size();++i) { if(s[i]==a) { ++cnt; if(i>0) { if(s[i-1]==s[i])++res; } } } if(cnt>(s.size()+1)>>1)pr(-1); else pr(res); } void sol4()//111 { vector<int> p; int res1=0,res2=0,cnt=0,now=0; bool flag1=0,flag2=0; string s1,s2; if(t[0]=='0')s1="11",s2="101"; else s1="00",s2="010"; for(int i=0;i<(int)s.size();i++) { if(s[i]==t[0])++now; else { p.push_back(now);now=0; if(i==0)res1+=1,flag1=1; if(!flag1&&i==1)res2+=1; if(i==(int)s.size()-1) { flag2=1,res1+=1; } if(!flag2&&s[(int)s.size()-2]!=t[0])res2+=1; if(i+1<s.size()) { if(s.substr(i,2)==s1)res1++; else if(i+2<s.size()) { if(s.substr(i,3)==s2)res2++; } } } } p.push_back(now); // cout<<res1<<" "<<res2<<endl; sort(p.begin(),p.end(),cmp); for(auto i:p) { if(i<3)continue; //if(i%2)continue; i-=2; // if(i==1&&res2){res2--;cnt++;continue;} if(res1>=(i>>1)){res1-=(i>>1);cnt+=(i>>1);i%=2;} else if(res1){i-=2*res1;cnt+=res1;res1=0;} if(!res2){res1-=(i+1)>>1;res2+=(i+1)>>1;}//没有101了可以尝试兑换一点11( cnt+=i; res2-=i; if(res2<0||res1<0){puts("-1");return;} } pr(cnt); } void sol5()//101 { int res=0; for(int i=0;i<(int)s.size()-2;++i) { if(s.substr(i,3)==t)++res; } res=(res+1)>>1; pr(res); } void sol6()//100&&110 { int res=0; for(int i=0;i<(int)s.size()-2;i++) { if(s.substr(i,3)==t)++res; } pr(res); } int main() { cin>>s;cin>>t; if(t.size()==1)sol1(); if(t.size()==2&&t[0]==t[1])sol3(); if(t.size()==2&&t[0]!=t[1])sol2(); if(t.size()==3&&t[0]==t[1]&&t[1]==t[2])sol4(); if(t.size()==3&&t[0]==t[2]&&t[0]!=t[1])sol5(); if(t.size()==3&&t[0]==t[1]&&t[1]!=t[2])sol6(); if(t.size()==3&&t[1]==t[2]&&t[0]!=t[1])sol6(); AC } ```