题意:
给你两个串s和t,其中t是由s中选择若干个不相交的区间翻转得到的,现在要求求出最少的翻转次数以及给出方案。
1≤|s|=|t|≤500000
题解:
我们将两个字符串合成成T=s1t1s2t2...sntn T=s1t1s2t2...sntn
那么问题就是最少要把整个字符串T 拆分成若干个偶数长度(并且长度大于2)的回文串。
长度是2的表示没有反转。
然后就变成了最小回文分解模型 ,然后直接上板子。
最小回文分解 论文在此
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map> #define pi acos(-1.0)
#define eps 1e-9
#define fi first
#define se second
#define rtl rt<<1
#define rtr rt<<1|1
#define bug printf("******\n")
#define mem(a, b) memset(a,b,sizeof(a))
#define name2str(x) #x
#define fuck(x) cout<<#x" = "<<x<<endl
#define sfi(a) scanf("%d", &a)
#define sffi(a, b) scanf("%d %d", &a, &b)
#define sfffi(a, b, c) scanf("%d %d %d", &a, &b, &c)
#define sffffi(a, b, c, d) scanf("%d %d %d %d", &a, &b, &c, &d)
#define sfL(a) scanf("%lld", &a)
#define sffL(a, b) scanf("%lld %lld", &a, &b)
#define sfffL(a, b, c) scanf("%lld %lld %lld", &a, &b, &c)
#define sffffL(a, b, c, d) scanf("%lld %lld %lld %lld", &a, &b, &c, &d)
#define sfs(a) scanf("%s", a)
#define sffs(a, b) scanf("%s %s", a, b)
#define sfffs(a, b, c) scanf("%s %s %s", a, b, c)
#define sffffs(a, b, c, d) scanf("%s %s %s %s", a, b,c, d)
#define FIN freopen("../in.txt","r",stdin)
#define gcd(a, b) __gcd(a,b)
#define lowbit(x) x&-x
#define IO iOS::sync_with_stdio(false) using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const ULL seed = ;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const int maxn = 1e6 + ;
const int maxm = 8e6 + ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
//最小回文分解
//根据题目需求求出分解成怎样的回文串
//本代码用于将串分解成最小数目的长度偶数回文的方案数
char s[maxn], s1[maxn], s2[maxn]; struct Palindrome_Automaton {
int len[maxn], next[maxn][], fail[maxn], cnt[maxn];
int num[maxn], S[maxn], sz, n, last;
int diff[maxn];//表示相邻回文后缀的等差;
int slk[maxn];//表示上一个等差数列的末项
int fp[maxn]; int newnode(int l) {
for (int i = ; i < ; ++i)next[sz][i] = ;
cnt[sz] = num[sz] = , len[sz] = l;
return sz++;
} void init() {
sz = n = last = ;
newnode();
newnode(-);
S[] = -;
fail[] = ;
} int get_fail(int x) {
while (S[n - len[x] - ] != S[n])x = fail[x];
return x;
} void add(int c, int pos) {
c -= 'a';
S[++n] = c;
int cur = get_fail(last);
if (!next[cur][c]) {
int now = newnode(len[cur] + );
fail[now] = next[get_fail(fail[cur])][c];
next[cur][c] = now;
num[now] = num[fail[now]] + ;
diff[now] = len[now] - len[fail[now]];
slk[now] = (diff[now] == diff[fail[now]] ? slk[fail[now]] : fail[now]);
}
last = next[cur][c];
cnt[last]++;
} //dp[i]表示s[1...i] s[1...i]s[1...i]的最少反转次数。
//pre[i] pre[i]pre[i]表示在最优解里面i为区间右端点的左端点下标。
void solve(int n, int *dp, int *pre) {
for (int i = ; i <= n; i++) dp[i] = INF, pre[i] = ;
init();
dp[] = , fp[] = ;
for (int i = ; i <= n; i++) {
add(s[i], i);
for (int j = last; j; j = slk[j]) {
fp[j] = i - len[slk[j]] - diff[j];
if (diff[j] == diff[fail[j]] && dp[fp[j]] > dp[fp[fail[j]]]) fp[j] = fp[fail[j]];
if (i % == && dp[i] > dp[fp[j]] + ) {//分解成 长度为偶数的回文串
dp[i] = dp[fp[j]] + ;
pre[i] = fp[j];
}
}
if (i % == && s[i] == s[i - ] && dp[i] >= dp[i - ]) {//长度是2的表示没有反转
dp[i] = dp[i - ];
pre[i] = i - ;
}
}
}
} pam; int dp[maxn], pre[maxn]; int main() {
// FIN;
sffs(s1 + , s2 + );
int n = * strlen(s1 + ), len1 = , len2 = ;
for (int i = ; i <= * n; i++) {
if (i & ) s[i] = s1[++len1];
else s[i] = s2[++len2];
}
// fuck(s + 1);
pam.solve(n, dp, pre);
if (dp[n] > n) return * printf("-1\n");
else printf("%d\n", dp[n]);
for (int i = n; i; i = pre[i])
if (i - pre[i] > ) printf("%d %d\n", pre[i] / + , i / );
return ;
}