问题描述:一个长度为3*n的01串,每次可以翻转连续的两个字符,要求至多翻转n次使得这个3*n的串至少有2*n个连续的段且相邻两端不一样(就是连续的0算一段,然后连续的1,…)
解法:每三个一组,只要能把每组分成两段而且和前面的不连着最后段数一定不小于2*n,例如前一个是1(0同理),当前组只有八种情况(冒号前表示操作前状态,冒号后表示操作后的状态):
000:011
001:001
010:010
011:011
100:010
101:101
110:101
111:001
故每种情况至多操作一次即可,扫一遍即得到操作位置
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<cmath> #include<vector> #include<queue> #include<map> #include<set> #include<ctime> using namespace std; typedef long long ll; #define INF 0x3f3f3f3f #define maxn 111111 char s[maxn*3]; int ans[maxn],res; int main() { while(~scanf("%s",s+1)) { s[0]='0'; int n=strlen(s+1); res=0; for(int i=1;i+2<=n;i+=3) { int a=s[i]-'0',b=s[i+1]-'0',c=s[i+2]-'0'; if(s[i-1]=='0') { if(a==0&&b==0&&c==0)ans[res++]=i; else if(a==0&&b==0&&c==1)ans[res++]=i+1,s[i+2]='0'; else if(a==0&&b==1&&c==1)ans[res++]=i; else if(a==1&&b==1&&c==1)ans[res++]=i+1,s[i+2]='0'; } else { if(a==0&&b==0&&c==0)ans[res++]=i+1,s[i+2]='1'; else if(a==1&&b==0&&c==0)ans[res++]=i; else if(a==1&&b==1&&c==0)ans[res++]=i+1,s[i+2]='1'; else if(a==1&&b==1&&c==1)ans[res++]=i; } } printf("%d ",res); for(int i=0;i<res;i++)printf("%d%c",ans[i],i==res-1?' ':' '); } return 0; }