题意:

已知某字符串\(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;//1int 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];}//2len = 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;
}

转载于:https://www.cnblogs.com/KirinSB/p/11281267.html

POJ 3581 Sequence(后缀数组)题解相关推荐

  1. POJ - 3581 Sequence(后缀数组)

    题目链接:点击查看 题目大意:给出一个数列,保证第一个数一定大于其余的所有数,现在需要让我们将其分为连续的三段,每一段独立反转后保证字典序最小,题目要求输出反转后字典序最小的数列 题目分析:因为第一个 ...

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

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

  3. POJ 3415 (后缀数组)

    被虐残了T_T.开始没思路,膜拜大牛的思路又看不懂...推荐一个题解:http://hi.baidu.com/fpkelejggfbfimd/item/5c76cfcba28fba26e90f2ea6 ...

  4. POJ 2217 Secretary (后缀数组)

    原题链接 Problem Description The basic condition of success of a political party, it is the good Electio ...

  5. POJ 2217 Secretary (后缀数组,挑战程序)

    题目意思: 给出两个字符串,要求两个字符串最长的公共子串(是子串不是子序列) 挑战程序设计竞赛, 383 页 本题要点: 1.高度数组,lcp[i] 表示后缀数组中,第i个字符串 S[sa[i] -] ...

  6. POJ - 1226 Substrings(后缀数组+二分)

    题目链接:点击查看 题目大意:给出n个字符串,求出n个字符串中或者在他们翻转过来的字符串中,出现的最长公共子串的长度 题目分析:说白了就是求n个字符串中的最长公共子串的变形,而这个变形也相当简单,只是 ...

  7. Musical Theme POJ - 1743(后缀数组+二分)

    求不可重叠最长重复子串 对于height[i]定义为sa[i]和 sa[i-1]的最长公共前缀 这个最长公共前缀的值肯定是最大的 证明: 设rank[j] < rank[k], 则不难证明后缀j ...

  8. POJ 1743 (后缀数组+不重叠最长重复子串)

    题目链接: http://poj.org/problem?id=1743 题目大意:楼教主の男人八题orz.一篇钢琴谱,每个旋律的值都在1~88以内.琴谱的某段会变调,也就是说某段的数可以加减一个旋律 ...

  9. poj 3261 后缀数组 找反复出现k次的子串(子串能够重叠)

    题目:http://poj.org/problem?id=3261 仍然是后缀数组的典型应用----后缀数组+lcp+二分 做的蛮顺的,1A 可是大部分时间是在调试代码.由于模板的全局变量用混了,而自 ...

  10. POJ - 3415 Common Substrings(后缀数组+单调栈)

    题目链接:点击查看 题目大意:给出两个字符串,再给出一个k,问两个字符串中长度大于等于k的公共子串有多少个(种类可重复) 题目分析:因为涉及到了子串问题,先用后缀数组跑出height数组来,接下来如果 ...

最新文章

  1. (C++)CSP202009-1 称检测点查询
  2. bzoj2875: [Noi2012]随机数生成器
  3. JAVA如何判断两个字符串是否相等(亲测第二种方式)
  4. CRMEB系统使用协议
  5. leetcode 413. Arithmetic Slices | 413. 等差数列划分(Java)
  6. 看到关于java资料比较全的,自己收藏
  7. C# 属性、索引器(二)
  8. c语言数组读心术,无聊的时候写的读心术小程序
  9. 十年风雨!看蚂蚁金服SOFA 分布式架构演进
  10. ASP.NET JS常用方法类
  11. python爬虫之模拟登陆csdn
  12. 盒子模型及层模型【定位】
  13. 哈希表实现电话号码查找系统
  14. python处理一段话,使他只存在英文,和数字
  15. 华为鸿蒙系统有没有畅玩7c,华为荣耀畅玩7C有什么新功能
  16. 2006德国世界杯完全赛程表
  17. jQuery菜鸟教程03
  18. 深度linux 官网,Deepin
  19. 安装Microsoft-project 2016
  20. 普通人如何应对经济危机

热门文章

  1. SGU 428 Rebus(构造)
  2. 管理Kubernetes集群时需要关注的关键指标
  3. noteless的博客导航页 所有文章的导航页面
  4. DataGrid相邻行有相同内容时对指定列合并和C#可以实现DLL库的动态调用
  5. 从 0 编写自己的第一款 IDEA 插件!
  6. IDEA 的这款插件真是逆天了,代码那都不是事!
  7. Linux 下 4 种禁用 Root 登陆的方法,你掌握了哪几种呢?
  8. CPU说:这个世界太慢了
  9. 到底该如何理解 Unix/Linux 的文件系统?看这篇就知道了
  10. 经济下行,薅点羊毛吧!