hdu 5442 后缀数组(没AC)
2016-02-21 22:59
453 查看
1.后缀数组果然很好用,而且利用height 对后缀分类也很好用
2.这题要注意的是,反过来再求后缀数组之后,是要求反过来<n 序号最大的最大后缀,和正着的不一样,最后再把序号返回去
3.下面是compile error的代码……谜一般啊!dev c++能过样例……
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
//正的和反的,分别求出后缀数组,从最大的开始,如果和前面的height==N那么判断和前面的哪个更靠近开头
//(注意反过来的情况),如果height < N 输出当前的ans,这样做就不要kmp了,后缀数组果然好用!不过我还不会o(n)的算法,不知道给不给我通过哈哈
//最后判断两个位置哪个结果更小,哪个更靠前
//为什么编译错误!!!去你的!
int sa[50000];
int height[50000];
int rank[50000];
int tem[50000];
string ans1,ans2;
int k;
int n;
bool compare(int i,int j)
{
if (rank[i] != rank[j]) return (rank[i] < rank[j]);
else{
int ri = (i + k) <= n?rank[i + k]:-1;
int rj = (j + k) <= n?rank[j + k]:-1;//这里的作用是,前k个都相等之后,如果有一个第k+1是第n位,有一个不是第n位,那么是第n位的比较大(rank
除了最开始,是等于0的?
return (ri < rj);
}
}
int make_sa(string s)
{
n = s.length();
for(int i = 0; i < n;i++){
sa[i] = i;
rank[i] = s[i];
}
rank
= -1;
sa
= n;
for(k = 1; k <= n; k *= 2){
sort(sa,sa + n + 1,compare);
tem[sa[0]] = 0;
for(int i = 1; i <= n; i++){
tem[sa[i]] = tem[sa[i - 1]] + compare(sa[i - 1],sa[i]);
}
for(int i = 0; i <= n; i++){
rank[i] = tem[i];
}
}
return 0;
}
int make_height(string s)
{
n = s.length();
height[sa[0]] = 0;
int h = 0;
for(int i = 0; i < n; i++){
int j = sa[rank[i] - 1];
if (h != 0) h--;
for(;j + h < n && i + h < n && s[j + h] == s[i + h];h++);
height[rank[i]] = h;
}
return 0;
}
int main()
{
int t;
string s1,s2;
s1 = "";s2 = "";
scanf("%d",&t);
while(t--){
int nn;
cin >> nn;
ans1 = "";ans2 = "";
cin >> s1;
for(int i = 0; i < n; i++)
s2 += s1[n - i - 1];
make_sa(s1 + s1);
make_height(s1 + s1);
n = s1.length();
for(int i = 0; i < n; i++)
ans1 += s1[(sa
+ i) % n];
int pos1 = sa
;
for(int i = n; i > 0; i++){ //从最大的开始
if (height[i] < n) break; //断了,不可能有再大的
else if (sa[i - 1] < n)
pos1 = min(pos1,sa[i - 1]);
}
make_sa(s2 + s2);
make_height(s2 + s2);
n = s1.length();
for(int i = 0; i < n; i++)
ans2 += s2[(sa
+ i) % n];
int pos2 = sa
;//最大的一定是从前面开始的无疑呀
for(int i = n; i > 0; i++){//
if (height[i] < n ) break;
else if (sa[i - 1] < n)
pos2 = max(pos2,sa[i - 1]);//越大的,本来就越小
}
pos2 = n - 1 - pos2;//变成本来的位置
if (ans1 < ans2 || (ans1 == ans2 && pos1 <= pos2)) printf("%d 0\n",pos1 + 1);
else printf("%d 1\n",pos2 + 1);
}
return 0;
}
2.这题要注意的是,反过来再求后缀数组之后,是要求反过来<n 序号最大的最大后缀,和正着的不一样,最后再把序号返回去
3.下面是compile error的代码……谜一般啊!dev c++能过样例……
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
//正的和反的,分别求出后缀数组,从最大的开始,如果和前面的height==N那么判断和前面的哪个更靠近开头
//(注意反过来的情况),如果height < N 输出当前的ans,这样做就不要kmp了,后缀数组果然好用!不过我还不会o(n)的算法,不知道给不给我通过哈哈
//最后判断两个位置哪个结果更小,哪个更靠前
//为什么编译错误!!!去你的!
int sa[50000];
int height[50000];
int rank[50000];
int tem[50000];
string ans1,ans2;
int k;
int n;
bool compare(int i,int j)
{
if (rank[i] != rank[j]) return (rank[i] < rank[j]);
else{
int ri = (i + k) <= n?rank[i + k]:-1;
int rj = (j + k) <= n?rank[j + k]:-1;//这里的作用是,前k个都相等之后,如果有一个第k+1是第n位,有一个不是第n位,那么是第n位的比较大(rank
除了最开始,是等于0的?
return (ri < rj);
}
}
int make_sa(string s)
{
n = s.length();
for(int i = 0; i < n;i++){
sa[i] = i;
rank[i] = s[i];
}
rank
= -1;
sa
= n;
for(k = 1; k <= n; k *= 2){
sort(sa,sa + n + 1,compare);
tem[sa[0]] = 0;
for(int i = 1; i <= n; i++){
tem[sa[i]] = tem[sa[i - 1]] + compare(sa[i - 1],sa[i]);
}
for(int i = 0; i <= n; i++){
rank[i] = tem[i];
}
}
return 0;
}
int make_height(string s)
{
n = s.length();
height[sa[0]] = 0;
int h = 0;
for(int i = 0; i < n; i++){
int j = sa[rank[i] - 1];
if (h != 0) h--;
for(;j + h < n && i + h < n && s[j + h] == s[i + h];h++);
height[rank[i]] = h;
}
return 0;
}
int main()
{
int t;
string s1,s2;
s1 = "";s2 = "";
scanf("%d",&t);
while(t--){
int nn;
cin >> nn;
ans1 = "";ans2 = "";
cin >> s1;
for(int i = 0; i < n; i++)
s2 += s1[n - i - 1];
make_sa(s1 + s1);
make_height(s1 + s1);
n = s1.length();
for(int i = 0; i < n; i++)
ans1 += s1[(sa
+ i) % n];
int pos1 = sa
;
for(int i = n; i > 0; i++){ //从最大的开始
if (height[i] < n) break; //断了,不可能有再大的
else if (sa[i - 1] < n)
pos1 = min(pos1,sa[i - 1]);
}
make_sa(s2 + s2);
make_height(s2 + s2);
n = s1.length();
for(int i = 0; i < n; i++)
ans2 += s2[(sa
+ i) % n];
int pos2 = sa
;//最大的一定是从前面开始的无疑呀
for(int i = n; i > 0; i++){//
if (height[i] < n ) break;
else if (sa[i - 1] < n)
pos2 = max(pos2,sa[i - 1]);//越大的,本来就越小
}
pos2 = n - 1 - pos2;//变成本来的位置
if (ans1 < ans2 || (ans1 == ans2 && pos1 <= pos2)) printf("%d 0\n",pos1 + 1);
else printf("%d 1\n",pos2 + 1);
}
return 0;
}
相关文章推荐
- 数据库链接字符串查询网站
- 书评:《算法之美( Algorithms to Live By )》
- 动易2006序列号破解算法公布
- Flex字符串比较 还有Flex字符串操作
- Ruby实现的矩阵连乘算法
- Ruby中创建字符串的一些技巧小结
- ASP下经常用的字符串等函数参考资料
- 将字符串小写转大写并延时输出的批处理代码
- 将字符串转换成System.Drawing.Color类型的方法
- C#插入法排序算法实例分析
- Lua源码中字符串类型的实现
- Lua性能优化技巧(四):关于字符串
- 字符串聚合函数(去除重复值)
- Ruby中的字符串编写示例
- 总结的5个C#字符串操作方法分享
- sqlserver中求字符串中汉字的个数的sql语句
- sql server字符串非空判断实现方法
- VBS的字符串及日期操作相关函数
- C#实现将千分位字符串转换成数字的方法
- jquery 删除字符串最后一个字符的方法解析