Reverses CodeForces - 906E (最小回文分解)
题意:
给你两个串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 ;
}
Reverses CodeForces - 906E (最小回文分解)的更多相关文章
- 【CF906E】Reverses(回文自动机,最小回文分割)
题意:给定两个长度相等的仅由小写字母组成的串A和B,问在A中最少选择多少段互不相交的子串进行翻转能使A和B相同 len<=5e5 思路:构造新串S=a[1]b[1]a[2]b[2]...a[n] ...
- 洛谷 P1609 最小回文数 题解
这题其实并不难,重点在你对回文数的了解,根本就不需要高精度. 打个比方: 对于一个形如 ABCDEFGH 的整数 有且仅有一个比它大的最小回文数 有且仅有一个比它小的最大回文数 而整数 ABCDDCB ...
- 洛谷——P1609 最小回文数
题目描述 回文数是从左向右读和从右向左读结果一样的数字串. 例如:121.44 和3是回文数,175和36不是. 对于一个给定的N,请你寻找一个回文数P,满足P>N. 满足这样条件的回文数很多, ...
- 洛谷—— P1609 最小回文数
https://www.luogu.org/problemnew/show/1609 题目描述 回文数是从左向右读和从右向左读结果一样的数字串. 例如:121.44 和3是回文数,175和36不是. ...
- CodeForces 17E Palisection(回文树)
E. Palisection time limit per test 2 seconds memory limit per test 128 megabytes input standard inpu ...
- 省选算法学习-回文自动机 && 回文树
前置知识 首先你得会manacher,并理解manacher为什么是对的(不用理解为什么它是$O(n)$,这个大概记住就好了,不过理解了更方便做$PAM$的题) 什么是回文自动机? 回文自动机(Pal ...
- 8633 回文划分(dp)
8633 回文划分 该题有题解 时间限制:1000MS 内存限制:1000K提交次数:169 通过次数:63 题型: 编程题 语言: G++;GCC Description 我们说一个字符串是回 ...
- C语言实现计算双基回文数详解
双基回文数的定义: 如果一个正整数n至少在两个不同的进位制(二进制<=进制=<十进制)b1和b2下都是回文数,则称n是双基回文数. 根据定义,简单的说就是在二进制到十进制之间(包括十进制和 ...
- [Swift]LeetCode866. 回文素数 | Prime Palindrome
Find the smallest prime palindrome greater than or equal to N. Recall that a number is prime if it's ...
随机推荐
- 本地JAR包打入本地mvn仓库
新建目录my-lib,将jar包移动到目录中,添加pom文件(用alipay测试) <project xmlns="http://maven.apache.org/POM/4.0.0& ...
- 剑指offer第二版面试题8:用两个栈实现队列(JAVA版)
题目:用两个栈实现一个队列.队列的声明如下,请实现它的两个函数appendTail和deletedHead,分别完成在队列尾部插入节点和在队列头部删除节点的功能. 分析: 我们通过一个具体的例子来分析 ...
- Linux中的网络管理——网络配置及命令
Linux网络配置 在Linux中配置IP地址的方法有以下这么几种: 图形界面配置IP地址(操作方式如Windows系统配置IP,但在实际生产中,我们并不建议在我们的服务器上安装Linux的图形界面, ...
- 33-Ubuntu-用户权限-04-修改目录权限
修改目录权限 例:test 1.可执行权限---x 减少目录x权限,无法切换到该目录 chmod -x test 2.读权限 ---r 减少目录r权限,无法读取(ls)目录信息 chmod -r te ...
- useradd -帐号建立或更新新使用者的资讯
总览 SYNOPSIS useradd [-c comment] [-d home_dir] [-e expire_date] [-f inactive_time] [-g initial_group ...
- netstat -pa --unix >>test.txt
netstat -pa --unix >>test.txt 输出套接字 命名socket信息
- JAVAWEB之文件的上传和下载
一.文件的上传: Enctype的属性介绍: 基于表单文件上传的界面简介: 文件上传时服务器端获取不到请求信息的原因及获取请求信息的几种方式: 输入流方式的实现: 实用工具包的实现:要导入fileup ...
- Go 位运算符
Go 位运算符 package main import "fmt" func main() { var a uint = 60 /* 60 = 0011 1100 */ var b ...
- kafaka集群部署
1.集群规划 kafka集群配置是依赖zookeeper的,所以需要保证先安装了zookeeper和jdk注意:kafka内自带zookeeper,我们不使用自带的. hadoop101 hadoop ...
- NX-二次开发删除对象UF_OBJ_delete_object
NX9+VS2012 #include <uf.h> #include <uf_curve.h> #include <uf_obj.h> UF_initialize ...