题意
给出两个串, s 和 t ,可以翻转 s 中的任意个不相交的区间,求变为 t 的最少操作次数
题解
变成 s1t1s2t2...sntn 的形式
转变为求最小的划分,使得每个部分都是回文串
Codeforces 932G 是求划分方案数的,这里把求和变为求最小值即可
注意
输出答案要把方案输出
所以,用 f[i] 不是表示 s[1...i]划分成的最少次数,而是表示需要翻转的最少次数
更新时,要增加判断
若 s[i]=s[i−1] ,说明原本的 s 和 t 对应位置是一样的,但是会误判成需要翻转一次,所以,需要 f[i]=f[i−2],path[i]=i−2
输出的时候,若 i−2==path[i] 说明实际上不需要翻转,跳过即可
代码
#include<bits/stdc++.h>
#define N 1000010
#define INF 0x3f3f3f3f
#define eps 1e-6
#define pi 3.141592653589793
#define mod 1000000007
#define P 1000000007
#define LL long long
#define pb push_back
#define fi first
#define se second
#define cl clear
#define si size
#define lb lower_bound
#define ub upper_bound
#define bug(x) cerr<<#x<<" : "<<x<<endl
#define mem(x,y) memset(x,0,sizeof(int)*(y+3))
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
typedef pair<int,int> pp;
int f[N],g[N],pa[N];
struct PAM {
int next[N][26] ;//next指针,next指针和字典树类似,指向的串为当前串两端加上同一个字符构成
int fail[N] ;//fail指针,失配后跳转到fail指针指向的节点
int len[N] ;//len[i]表示节点i表示的回文串的长度
int s[N] ;//存放添加的字符
int last ;//指向上一个字符所在的节点,方便下一次add
int n ;//字符数组指针
int p ;//节点指针
int d[N],up[N],id[N];
inline int newnode ( int l ) {//新建节点
for ( int i = 0 ; i < 26 ; ++ i ) next[p][i] = 0 ;
len[p] = l ;
return p ++ ;
}
inline void init () {//初始化
p = 0 ;
newnode ( 0 ) ;
newnode ( -1 ) ;
last = 0 ;
n = 0 ;
s[n] = -1 ;//开头放一个字符集中没有的字符,减少特判
fail[0] = 1 ;
}
inline int get_fail ( int x ) {//和KMP一样,失配后找一个尽量最长的
while ( s[n - len[x] - 1] != s[n] ) x = fail[x] ;
return x ;
}
inline void add ( int c,int w ) {
c -= 'a' ;
s[++ n] = c ;
int cur = get_fail ( last ) ;//通过上一个回文串找这个回文串的匹配位置
if ( !next[cur][c] ) {//如果这个回文串没有出现过,说明出现了一个新的本质不同的回文串
int now = newnode ( len[cur] + 2 ) ;//新建节点
fail[now] = next[get_fail ( fail[cur] )][c] ;
next[cur][c] = now ;
d[now]=len[now]-len[fail[now]];
up[now]=(d[fail[now]]==d[now]?up[fail[now]]:now);
}
last = next[cur][c] ;
id[w]=last;
}
void slove(){
for(int i=1;i<=n;i++){
for(int j=id[i];j;j=fail[up[j]]){
g[j]=i-len[up[j]];
if (d[j]==d[fail[j]]&&f[g[fail[j]]]<f[g[j]]) g[j]=g[fail[j]];
if (!(i&1)&&f[g[j]]+1<f[i]){
f[i]=f[g[j]]+1;
pa[i]=g[j];
}
}
if (!(i&1)&&s[i]==s[i-1]){
f[i]=f[i-2];
pa[i]=i-2;
}
}
}
}A;
char s[N],t[N];
char ss[N];
int main(int argc, char const *argv[]){
scanf("%s%s",s+1,t+1);
int n=strlen(s+1);
for(int i=1;i<=n*2;i+=2) ss[i]=s[i/2+1],ss[i+1]=t[i/2+1];
A.init();
n<<=1;
for(int i=1;i<=n;i++) A.add(ss[i],i);
memset(f,INF,sizeof(int)*(n+3));
f[0]=0;
A.slove();
if (f[n]>n) puts("-1");else{
printf("%d\n",f[n]);
for(int i=n;i;i=pa[i])
if (i-pa[i]>2)printf("%d %d\n",pa[i]/2+1,i/2);
}
return 0;
}