问题:初始有个标识符S,可以进行两种操作: 1 将第pos 个标识符S变成0S1S。 2 将第pos 个标识符S变成1S0S。 最终所有的标识符消失,只保留字符串中的01字符。 现在给出01串T,问能否生成,如果能生成输出操作次数与步骤,如果不能,输出-1。 1 ≤|T| ≤ 106。
样例:输入:0011
输出:2
1 1
1 1
样例解释:最初为S,第一次操作1 1,得到0S1S.第二次操作1 1,得到00S1S1S,最后操作符消失,得到0011.
解答:首先不难发现,每次将标识符变为0S1S或者1S0S时,0,1都是成对增加,因此最终生成的01串必然满足字符0的数量等于字符1的数量,同时操作次数必然为T/2,故而可以将num0与num1是否相等视作一种验证能否生成的方法,可以在输入01串之后判断一下,如果不相等直接输出-1并返回。
之后观察发现,S的位置相对于单次操作后总是出现在相对位置后的第2个,第4个位置,故而可以很轻易的通过S调整0,1出现的位置,因此可以大胆假设出,只要0,1的个数相等,便可以轻易的通过S生成相应的0,1串。那么不妨把处理整个大的01串的问题转化为大01串中连续且0,1个数相等的小01串问题,即“划分子问题”。
于是乎对于子串,就有以下两种情况,01(10)连续,与01(10)不连续(出现00,11),于是可以想到利用栈容器(stack)进行捕捉和模拟是否出现连续,当遇到与栈顶相同的数时,将其入栈,相当于对新的标识符进行操作,当遇到不同的符号时,将其出栈,模拟标识符消失的过程,并更新下次操作S的位置,这样就能通过栈来模拟整个操作过程,确定每次针对的标识符位置和类型。
AC代码如下:
#include <bits/stdc++.h>
using namespace std;
#define int long long
string str;
stack <char>sta;
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>str;
int num1=count(str.begin(),str.end(),'1');
int num0=count(str.begin(),str.end(),'0');
//判断0,1数是否相等
if(num1!=num0)
{
cout<<-1<<endl;
return 0;
}
//输出操作数,即01串长度的一半
cout<<num1<<endl;
int i=0;//遍历下标
int pos=1;//所要更改的S的位置
while(i<str.size())
{
char c=str[i];
if(sta.empty()||sta.top()==c)
{
//相等入栈,操作新的标识符
sta.push(c);
cout<<pos<<" "<<c-'0'+1<<endl;
}
else
{
//不相等出栈,改变要操作的S的位置
sta.pop();
pos++;
}
i++;
}
return 0;
}
由于本蒟蒻实力有限,无法补完所有的题,故只能选做且一个一个发题解,望谅解。
最后嘞------求点赞关注!! !