Luogu P6303 [eJOI2018]AB 串 题解
Posted acceptedzhs
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu P6303 [eJOI2018]AB 串 题解相关的知识,希望对你有一定的参考价值。
首先,我们可以发现一个性质:
每一次交换的前缀,必然是该串由相同字母构成的最长前缀,或者空串。
什么意思呢?比如,对于串 (aaabb) ,显然选 (aa) 没有 (aaa) 划算。
接下来,我们要分两种情况讨论:
1. 两串首字母不同
如: (aaaaabb) 与 (bbbbbaa) ,直接选两串的由相同字母构成的最长前缀,即 (aaaaa) 与 (bbbbb) 交换即可。
2. 两串首字母相同
如: (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
",step);
for(int i=1;i<=step;i++) printf("%d %d
",ans[i][0],ans[i][1]);
return 0;
}
以上是关于Luogu P6303 [eJOI2018]AB 串 题解的主要内容,如果未能解决你的问题,请参考以下文章