标签:cpp scan strong 相同 mat code 直接 mes name
首先,我们可以发现一个性质:
每一次交换的前缀,必然是该串由相同字母构成的最长前缀,或者空串。
什么意思呢?比如,对于串 \(aaabb\) ,显然选 \(aa\) 没有 \(aaa\) 划算。
接下来,我们要分两种情况讨论:
如: \(aaaaabb\) 与 \(bbbbbaa\) ,直接选两串的由相同字母构成的最长前缀,即 \(aaaaa\) 与 \(bbbbb\) 交换即可。
如: \(aaaaabb\) 与 \(ababababa\) 。显然,我们不能选两串的由相同字母构成的最长前缀了。我们考虑把其中一个换成空串 (要不 \(rand\) 一下?),此时就转化为第一种情况了。但是——
对于串 \(aaaaabb\) 与 \(aaaaa\) ,显然我们选第二个串为空串。这种情况特判一下即可。
然而,这样如果暴力修改,显然会超时。
我们考虑把串分段,每一段中字母都相同。如: \(aaaabbbbaaba\) 可分成\(5\)段:\(aaaa|bbbb|aa|b|a\)。
修改操作就极为容易了,把两个串的第一段交换,或者把一个串的第一段挪到另一个串开头,然后合并段即可。
如:串 \(aaaabbbbaaba\) 与 \(bbbaaab\) ,
先分段:\(aaaa|bbbb|aa|b|a\) 与 \(bbb|aaa|b\)
交换:\(bbb|bbbb|aa|b|a\) 与 \(aaaa|aaa|b\)
合并前面的段:\(bbbbbbb|aa|b|a\) 与 \(aaaaaaa|b\)
就这样循环,直到两串段数都为\(1\)(即字符都相同了)退出循环就行啦!
最后注意一下,由于要在串的开头增加元素,所以要开个双端队列。
\(Code:\)
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,lena,lenb,ans[1000005][2];
int heada=1e6+1,taila=1e6,headb=1e6+1,tailb=1e6,step; //两个双端队列的首尾
char a[5000005],b[5000005];
struct Block{ //段
int typ,len;
}c[2][10000005];
int main(){
scanf("%s%s",a+1,b+1);
lena=strlen(a+1),lenb=strlen(b+1);
int last=-1; //分段
for(int i=1;i<=lena;i++){
if(last!=a[i]-‘a‘){
c[0][++taila].typ=a[i]-‘a‘;
c[0][taila].len=1;
last=a[i]-‘a‘;
}
else c[0][taila].len++;
}
last=-1;
for(int i=1;i<=lenb;i++){
if(last!=b[i]-‘a‘){
c[1][++tailb].typ=b[i]-‘a‘;
c[1][tailb].len=1;
last=b[i]-‘a‘;
}
else c[1][tailb].len++;
}
while(true){
if(heada==taila&&headb==tailb) break; //都只有一段了,直接退出
step++;
if(c[0][heada].typ!=c[1][headb].typ){
ans[step][0]=c[0][heada].len,ans[step][1]=c[1][headb].len;//记录答案
swap(c[0][heada],c[1][headb]);
int sum=c[0][heada].len,j; //合并
for(j=heada+1;j<=taila;j++){
if(c[0][j].typ==c[0][heada].typ) sum+=c[0][j].len;
else break;
}
--j;c[0][heada=j].len=sum;
sum=c[1][headb].len;
for(j=headb+1;j<=tailb;j++){
if(c[1][j].typ==c[1][headb].typ) sum+=c[1][j].len;
else break;
}
--j;c[1][headb=j].len=sum;
continue;
}
else{
int from;
if(heada==taila) from=1;
else from=0; //判断把哪个串换成空串
if(from){
ans[step][0]=0,ans[step][1]=c[1][headb].len;
c[0][--heada]=c[1][headb];headb++;
}
else{
ans[step][0]=c[0][heada].len,ans[step][1]=0;
c[1][--headb]=c[0][heada];heada++;
}
int sum=c[0][heada].len,j;
for(j=heada+1;j<=taila;j++){
if(c[0][j].typ==c[0][heada].typ) sum+=c[0][j].len;
else break;
}
--j;c[0][heada=j].len=sum;
sum=c[1][headb].len;
for(j=headb+1;j<=tailb;j++){
if(c[1][j].typ==c[1][headb].typ) sum+=c[1][j].len;
else break;
}
--j;c[1][headb=j].len=sum;
continue;
}
}
printf("%d\n",step);
for(int i=1;i<=step;i++) printf("%d %d\n",ans[i][0],ans[i][1]);
return 0;
}
【Luogu】 P6303 [eJOI2018]AB 串 题解
标签:cpp scan strong 相同 mat code 直接 mes name
原文地址:https://www.cnblogs.com/acceptedzhs/p/13036840.html