题意:

已知某字符串\(str\)满足\(str_1 > max\{str_2,str_3 \cdots str_n\}\),现要求把这个字符串分成连续的三组,然后每组都翻转,问字典序最小是什么?

思路:

因为\(str_1 > max\{str_2,str_3 \cdots str_n\}\),所以第一部分直接翻转后跑\(sa\)求字典序最小就行了。那么现在问题转化为:把这个字符串分成两半,然后每组都翻转,问字典序最小是什么?

我们假设这个字符串为\(s_1s_2 \cdots s_n\),那么可以得到分成两半反转后为\(s_ks_{k-1}s_{k-2} \cdots s_1s_ns_{n-1} \cdots s_{k+1}\),我们可以发现,这个串其实就是\(s_ns_{n-1}s_{n-2} \cdots s_1s_ns_{n-1} \cdots s_{1}\)的一个子串,那么我就把这个串反向复制两遍,然后后缀数组求字典序最小即可。

tips:多组输入必wa

代码:

#include<map>
#include<set>
#include<queue>
#include<cmath>
#include<stack>
#include<ctime>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 4e5 + 10;
const int INF = 0x3f3f3f3f;
const ull seed = 11;
const int MOD = 1e9 + 7;
using namespace std; int str[maxn];
int t1[maxn], t2[maxn], c[maxn];
int sa[maxn];
int rk[maxn];
int height[maxn];
bool cmp(int *r, int a, int b, int l){
return r[a] == r[b] && r[a + l] == r[b + l];
}
void da(int *str, int n, int m){
n++;
int i, j, p, *x = t1, *y = t2;
for(i = 0; i < m; i++) c[i] = 0;
for(i = 0; i < n; i++) c[x[i] = str[i]]++;
for(i = 1; i < m; i++) c[i] += c[i - 1];
for(i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i;
for(j = 1; j <= n; j <<= 1){
p = 0;
for(i = n - j; i < n; i++) y[p++] = i;
for(i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i] - j;
for(i = 0; i < m; i++) c[i] = 0;
for(i = 0; i < n; i++) c[x[y[i]]]++;
for(i = 1; i < m; i++) c[i] += c[i - 1];
for(i = n - 1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];
swap(x, y);
p = 1; x[sa[0]] = 0;
for(i = 1; i < n; i++)
x[sa[i]] = cmp(y, sa[i - 1], sa[i], j)? p - 1 : p++;
if(p >= n) break;
m = p;
}
// int k = 0;
// n--;
// for(i = 0; i <= n; i++) rk[sa[i]] = i;
// for(i = 0; i < n; i++){
// if(k) k--;
// j = sa[rk[i] - 1];
// while(str[i + k] == str[j + k]) k++;
// height[rk[i]] = k;
// }
}
vector<int> vv;
int s[maxn];
int ans[maxn];
int main(){
int n;
int Max;
scanf("%d", &n);
vv.clear();
for(int i = 1; i <= n; i++) scanf("%d", &s[i]), vv.push_back(s[i]);
sort(vv.begin(), vv.end());
vv.erase(unique(vv.begin(), vv.end()), vv.end());
for(int i = 1; i <= n; i++){
s[i] = lower_bound(vv.begin(), vv.end(), s[i]) - vv.begin() + 1;
}
Max = vv.size() + 2;
//1
int len = n - 2;
int cnt = 0;
for(int i = len, j = 0; i >= 1; i--, j++){
str[j] = s[i];
}
str[len] = 0;
da(str, len, Max);
for(int i = sa[1]; i < len; i++){
ans[cnt++] = str[i];
}
//2
len = 0;
for(int i = n; i > cnt; i--){
str[len++] = s[i];
}
for(int i = n; i > cnt; i--){
str[len++] = s[i];
}
str[len] = 0;
da(str, len, Max);
int st;
for(int i = 1; ; i++){
if(sa[i] < len / 2 && sa[i] != 0){
st = sa[i];
break;
}
}
for(int i = st; cnt < n; i++){
ans[cnt++] = str[i];
}
for(int i = 0; i < cnt; i++){
printf("%d\n", vv[ans[i] - 1]);
}
return 0;
}

POJ 3581 Sequence(后缀数组)题解的更多相关文章

  1. POJ 3581 Sequence(后缀数组)

    Description Given a sequence, {A1, A2, ..., An} which is guaranteed A1 > A2, ..., An,  you are to ...

  2. POJ 3581 Sequence ——后缀数组 最小表示法

    [题目分析] 一见到题目,就有了一个显而易见obviously的想法.只需要每次找到倒过来最小的那一个字符串翻转就可以了. 然而事情并不是这样的,比如说505023这样一个字符串,如果翻转了成为320 ...

  3. POJ 3581 Sequence [后缀数组]

    Sequence Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 6911   Accepted: 1543 Case Tim ...

  4. [POJ 3581]Sequence

    [POJ 3581]Sequence 标签: 后缀数组 题目链接 题意 给你一串序列\(A_i\),保证对于$ \forall i \in [2,n],都有A_1 >A_i$. 现在需要把这个序 ...

  5. kuangbin带你飞 后缀数组 题解

    2份模板 DC3 . 空间复杂度O3N 时间复杂度On #define F(x) ((x) / 3 + ((x) % 3 == 1 ? 0 : tb)) #define G(x) ((x) < ...

  6. 后缀数组 POJ 3581 Sequence

    题目链接 题意:把n个数字(A1比其他数字都大)的序列分成三段,每段分别反转,问字典序最小的序列. 分析:因为A1比其他数字都大,所以反转后第一段结尾是很大的数,相当是天然的分割线,第一段可以单独考虑 ...

  7. POJ3581 Sequence —— 后缀数组

    题目链接:https://vjudge.net/problem/POJ-3581 Sequence Time Limit: 5000MS   Memory Limit: 65536K Total Su ...

  8. POJ - 1226 Substrings (后缀数组)

    传送门:POJ - 1226 这个题跟POJ - 3294  和POJ - 3450 都是一样的思路,一种题型. POJ - 3294的题解可以见:https://www.cnblogs.com/li ...

  9. POJ 2406 KMP/后缀数组

    题目链接:http://poj.org/problem?id=2406 题意:给定一个字符串,求由一个子串循环n次后可得到原串,输出n[即输出字符串的最大循环次数] 思路一:KMP求最小循环机,然后就 ...

随机推荐

  1. 入门OJ:郭嘉的消息传递

    题目描述 我们的郭嘉大大在曹操这过得逍遥自在,但是有一天曹操给了他一个任务,在建邺城内有N(<=1000)个袁绍的奸细 将他们从1到N进行编号,同时他们之间存在一种传递关系,即若C[i,j]=1 ...

  2. 从synchronized和lock区别入手聊聊java锁机制

    写这篇文章之前,我去百度了一下啥叫锁,百度百科上写道:置于可启闭的器物上,以钥匙或暗码开启.确实我们一般理解的锁就是门锁,密码锁,但是在计算机科学中,锁又是啥,说实话,这个问题我也思考了很久,也没法很 ...

  3. Java SPI机制详解

    Java SPI机制详解 1.什么是SPI? SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制.SPI是一种动态替换发现的机制, 比如有个 ...

  4. Boyer-Moore 投票算法

    Boyer-Moore 投票算法 http://theory.stanford.edu/~trevisan/cs154-12/notestream.pdf 众数

  5. BI学习向导文章

    BI的学习笔记: BIWORK的博客:http://www.cnblogs.com/biwork/p/3328879.html 邀月工作室博客 :http://www.cnblogs.com/down ...

  6. Java NIO ———— Buffer 缓冲区详解 入门

    引言缓冲区是一个用于特定基本类型的容器.由java.nio 包定义,所有缓冲区都是 Buffer 抽象类的子类. Java NIO 中的 Buffer ,主要用于与NIO 通道进行交互.数据从通道存入 ...

  7. Kubernetes TensorFlow 默认 特定 集群管理器 虚拟化技术

    Our goal is to foster an ecosystem of components and tools that relieve the burden of running applic ...

  8. 20201115gryz模拟赛解题报告

    写在前面 T1:期望100pts,实际0pts(7:50 ~ 8:50 T2:期望0pts,实际0pts(10:00 ~ 10:35 T3:期望20pts,实际40pts( 9:10 ~ 10:00, ...

  9. loj10005数列极差

    题目描述 佳佳的老师在黑板上写了一个由  n个正整数组成的数列,要求佳佳进行如下操作:每次擦去其中的两个数 a 和 b,然后在数列中加入一个数 a*b+1,如此下去直至黑板上剩下一个数为止,在所有按这 ...

  10. python 利用正则表达式获取IP地址

    例:import retest= '$MYNETACT: 0,1,"10.10.0.9"'pattern =re.compile(r'"(\d+\.\d+\.\d+\.\ ...