Reverses CodeForces - 906E (最小回文分解)

题意:

给你两个串s和t,其中t是由s中选择若干个不相交的区间翻转得到的,现在要求求出最少的翻转次数以及给出方案。 
1≤|s|=|t|≤500000

题解:

我们将两个字符串合成成T=s1t1s2t2...sntn T=s1t1s2t2...sntn

那么问题就是最少要把整个字符串T 拆分成若干个偶数长度(并且长度大于2)的回文串。
长度是2的表示没有反转。
然后就变成了最小回文分解模型 ,然后直接上板子。

最小回文分解 论文在此

  1 #include <set>
  2 #include <map>
  3 #include <stack>
  4 #include <queue>
  5 #include <cmath>
  6 #include <ctime>
  7 #include <cstdio>
  8 #include <string>
  9 #include <vector>
 10 #include <cstring>
 11 #include <iostream>
 12 #include <algorithm>
 13 #include <unordered_map>
 14
 15 #define  pi    acos(-1.0)
 16 #define  eps   1e-9
 17 #define  fi    first
 18 #define  se    second
 19 #define  rtl   rt<<1
 20 #define  rtr   rt<<1|1
 21 #define  bug                printf("******\n")
 22 #define  mem(a, b)          memset(a,b,sizeof(a))
 23 #define  name2str(x)        #x
 24 #define  fuck(x)            cout<<#x" = "<<x<<endl
 25 #define  sfi(a)             scanf("%d", &a)
 26 #define  sffi(a, b)         scanf("%d %d", &a, &b)
 27 #define  sfffi(a, b, c)     scanf("%d %d %d", &a, &b, &c)
 28 #define  sffffi(a, b, c, d) scanf("%d %d %d %d", &a, &b, &c, &d)
 29 #define  sfL(a)             scanf("%lld", &a)
 30 #define  sffL(a, b)         scanf("%lld %lld", &a, &b)
 31 #define  sfffL(a, b, c)     scanf("%lld %lld %lld", &a, &b, &c)
 32 #define  sffffL(a, b, c, d) scanf("%lld %lld %lld %lld", &a, &b, &c, &d)
 33 #define  sfs(a)             scanf("%s", a)
 34 #define  sffs(a, b)         scanf("%s %s", a, b)
 35 #define  sfffs(a, b, c)     scanf("%s %s %s", a, b, c)
 36 #define  sffffs(a, b, c, d) scanf("%s %s %s %s", a, b,c, d)
 37 #define  FIN                freopen("../in.txt","r",stdin)
 38 #define  gcd(a, b)          __gcd(a,b)
 39 #define  lowbit(x)          x&-x
 40 #define  IO                 iOS::sync_with_stdio(false)
 41
 42
 43 using namespace std;
 44 typedef long long LL;
 45 typedef unsigned long long ULL;
 46 const ULL seed = 13331;
 47 const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
 48 const int maxn = 1e6 + 7;
 49 const int maxm = 8e6 + 10;
 50 const int INF = 0x3f3f3f3f;
 51 const int mod = 1e9 + 7;
 52 //最小回文分解
 53 //根据题目需求求出分解成怎样的回文串
 54 //本代码用于将串分解成最小数目的长度偶数回文的方案数
 55 char s[maxn], s1[maxn], s2[maxn];
 56
 57 struct Palindrome_Automaton {
 58     int len[maxn], next[maxn][26], fail[maxn], cnt[maxn];
 59     int num[maxn], S[maxn], sz, n, last;
 60     int diff[maxn];//表示相邻回文后缀的等差;
 61     int slk[maxn];//表示上一个等差数列的末项
 62     int fp[maxn];
 63
 64     int newnode(int l) {
 65         for (int i = 0; i < 26; ++i)next[sz][i] = 0;
 66         cnt[sz] = num[sz] = 0, len[sz] = l;
 67         return sz++;
 68     }
 69
 70     void init() {
 71         sz = n = last = 0;
 72         newnode(0);
 73         newnode(-1);
 74         S[0] = -1;
 75         fail[0] = 1;
 76     }
 77
 78     int get_fail(int x) {
 79         while (S[n - len[x] - 1] != S[n])x = fail[x];
 80         return x;
 81     }
 82
 83     void add(int c, int pos) {
 84         c -= ‘a‘;
 85         S[++n] = c;
 86         int cur = get_fail(last);
 87         if (!next[cur][c]) {
 88             int now = newnode(len[cur] + 2);
 89             fail[now] = next[get_fail(fail[cur])][c];
 90             next[cur][c] = now;
 91             num[now] = num[fail[now]] + 1;
 92             diff[now] = len[now] - len[fail[now]];
 93             slk[now] = (diff[now] == diff[fail[now]] ? slk[fail[now]] : fail[now]);
 94         }
 95         last = next[cur][c];
 96         cnt[last]++;
 97     }
 98
 99     //dp[i]表示s[1...i] s[1...i]s[1...i]的最少反转次数。
100     //pre[i] pre[i]pre[i]表示在最优解里面i为区间右端点的左端点下标。
101     void solve(int n, int *dp, int *pre) {
102         for (int i = 0; i <= n; i++) dp[i] = INF, pre[i] = 0;
103         init();
104         dp[0] = 0, fp[0] = 1;
105         for (int i = 1; i <= n; i++) {
106             add(s[i], i);
107             for (int j = last; j; j = slk[j]) {
108                 fp[j] = i - len[slk[j]] - diff[j];
109                 if (diff[j] == diff[fail[j]] && dp[fp[j]] > dp[fp[fail[j]]]) fp[j] = fp[fail[j]];
110                 if (i % 2 == 0 && dp[i] > dp[fp[j]] + 1) {//分解成 长度为偶数的回文串
111                     dp[i] = dp[fp[j]] + 1;
112                     pre[i] = fp[j];
113                 }
114             }
115             if (i % 2 == 0 && s[i] == s[i - 1] && dp[i] >= dp[i - 2]) {//长度是2的表示没有反转
116                 dp[i] = dp[i - 2];
117                 pre[i] = i - 2;
118             }
119         }
120     }
121 } pam;
122
123 int dp[maxn], pre[maxn];
124
125 int main() {
126     // FIN;
127     sffs(s1 + 1, s2 + 1);
128     int n = 2 * strlen(s1 + 1), len1 = 0, len2 = 0;
129     for (int i = 1; i <= 2 * n; i++) {
130         if (i & 1) s[i] = s1[++len1];
131         else s[i] = s2[++len2];
132     }
133     // fuck(s + 1);
134     pam.solve(n, dp, pre);
135     if (dp[n] > n) return 0 * printf("-1\n");
136     else printf("%d\n", dp[n]);
137     for (int i = n; i; i = pre[i])
138         if (i - pre[i] > 2) printf("%d %d\n", pre[i] / 2 + 1, i / 2);
139     return 0;
140 }

原文地址:https://www.cnblogs.com/qldabiaoge/p/11403882.html

时间: 2024-10-14 19:52:08

Reverses CodeForces - 906E (最小回文分解)的相关文章

【CF906E】Reverses(回文自动机,最小回文分割)

题意:给定两个长度相等的仅由小写字母组成的串A和B,问在A中最少选择多少段互不相交的子串进行翻转能使A和B相同 len<=5e5 思路:构造新串S=a[1]b[1]a[2]b[2]...a[n]b[n] 问题等价于求S的最小回文分割,其中需要每一段的长度都为偶数,注意长度为2的相当于没有翻转 把板子稍加修改即可 1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 typedef unsign

C语言找出大于一个数的最小回文数的代码

下面代码内容是关于C语言找出大于一个数的最小回文数的代码,希望能对码农们有用途. #include <stdio.h>#include <stdlib.h>#include <string.h> void main(){char data[10] = {0}, res[10] = {0}, state[10] = {0}, len = 0, pos, bit = 0;scanf("%s",data); len = strlen(data); pos

洛谷——P1609 最小回文数

题目描述 回文数是从左向右读和从右向左读结果一样的数字串. 例如:121.44 和3是回文数,175和36不是. 对于一个给定的N,请你寻找一个回文数P,满足P>N. 满足这样条件的回文数很多,你的任务是输出其中最小的一个. 输入输出格式 输入格式: 1行,一个正整数N.N的数值小于10^100,并且N没有前导0. 输出格式: 你的程序应该输出一行,最小的回文数P(P>N). 输入输出样例 输入样例#1: 复制 44 输出样例#1: 复制 55 说明 50%的数据,N<10^9 100%

CodeForces 17E Palisection(回文树)

E. Palisection time limit per test 2 seconds memory limit per test 128 megabytes input standard input output standard output In an English class Nick had nothing to do at all, and remembered about wonderful strings called palindromes. We should remin

算法学习笔记——判断最小回文子串

利用C语言实现的最长回文子串算法 1 # include<stdio.h> 2 # include<string.h> 3 # include<ctype.h> 4 5 # define MAXN 5000 + 10 6 char buf[MAXN], s[MAXN]; //buf输入字符串, s去掉标点空格并转为大写的预处理字符串 7 int p[MAXN]; // p用于记录处理后字符串s中,每个字符在原字符串buf中的序号 8 int main(){ 9 10 i

回文串划分

题目: 有一个字符串S,求S最少可以被划分为多少个回文串. 例如:abbaabaa,有多种划分方式. a|bb|aabaa - 3 个回文串 a|bb|a|aba|a - 5 个回文串 a|b|b|a|a|b|a|a - 8 个回文串 其中第1种划分方式的划分数量最少. Input 输入字符串S(S的长度<= 5000). Output 输出最少的划分数量. Sample Input abbaabaa Sample Output 3 分析:题目意思还是很好懂的,不像比赛的几个题目我连题意都没看懂

hihoCoder hiho一下 第一周 #1032 : 最长回文子串 (特殊处理)

思路: (1)暴力穷举.O(n^3) -----绝对不行. 穷举所有可能的出现子串O(n^2),再判断是否回文O(n).就是O(n*n*n)了. (2)记录位置.O(n^3) -----绝对不行. 先扫一遍,记录每个字符在上一次出现的位置pos.每次考虑第i个字符,如果回文子串包括 i 的话,那么肯定在i的前面有一个跟第i个字符是一样的,利用之前记录的位置pos[i]可以找到与第i个相同的字符,如果i-pos[i]比之前发现的最长的子串max还短,那么不用比较了.如果更前面还有和第i个字符一样的

UVA - 11584 划分字符串的回文串子串; 简单dp

/** 链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=34398 UVA - 11584 划分字符串的回文串子串: 简单dp 题目大意: 给一个字符串, 要求把它分割成若干个子串,使得每个子串都是回文串.问最少可以分割成多少个. 定义:dp[i]表示前0~i内的字符串划分成的最小回文串个数: dp[i] = min(dp[j]+1 | j+1~i是回文串); 先预处理flag[i][j]表示以i~j内的字符串为回文串

回文数问题

问题描述 我在2008年6月写了一篇随笔"可以使用C#语言的在线ACM题库",其中提到 Sphere Onlile Judge (SPOJ) 网站.现在我们来看看该网站 SPOJ Problem Set (classical) 中的"5. The Next Palindrome".这道题目的主要内容如下所示: The Next Palindrome: A positive integer is called a palindrome if its represent