题意:找一个出现了m次的最长子串,以及这时的最右的位置。

  hash的话代码还是比较好写的,,但是时间比SA多很多。。

 #include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
const int N = + ;
typedef long long ll;
const int X = ;
const int mod = (int)1e9 + ; char s[N];
int m,len,pw[N];
int H[N],pos; struct node
{
int id,hash;
bool operator < (const node & temp) const
{
return hash == temp.hash ? id < temp.id : hash < temp.hash;
}
}p[N]; bool solve(int L)
{
int cnt = ;
pos = -;
for(int i=;i+L-<=len;i++)
{
int id = i;
int hash = ((ll)H[i] - (ll)H[i+L]*pw[L]) % mod;
if(hash < ) hash += mod; // 注意这里!
p[i] = (node){id, hash};
}
sort(p+, p++ len - L + ); for(int i=;i<=len-L+;i++)
{
if(i == || p[i].hash != p[i-].hash) cnt = ;
if(++cnt >= m) pos = max(pos, p[i].id);
}
return pos != -;
} int main()
{
pw[] = ;
for(int i=;i<N;i++) pw[i] = 1LL*pw[i-] * X % mod;
while(scanf("%d",&m) == && m)
{
scanf("%s",s+);
len = strlen(s+);
for(int i=len;i>=;i--) H[i] = (1LL*H[i+] * X + s[i] - 'a') % mod;
int l = , r = len, ans = -;
while(l <= r)
{
int mid = l + r >> ;
if(solve(mid)) ans = mid, l = mid + ;
else r = mid - ;
}
solve(ans);
if(ans != -) printf("%d %d\n",ans, pos-);
else puts("none");
}
return ;
}

hash的写法

  

  SA的话,写法需要细细体会一下了。。时间减少了很多。

 #include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
const int N = + ;
typedef long long ll; /**
* sa[i]:表示排在第i位的后缀的起始下标
* rank[i]:表示后缀suffix(i)排在第几
* height[i]:sa[i-1] 与 sa[i]的LCP(最长公共前缀)值
*
* */
/*
如果整数的话模板改成int.
加一个数a[n] = 0 。 这样他的排名是第一个。
construct(a,n+1); 字符串的话。
len = strlen(str);
construct(s,strlen(s)+1);
排名第0的是个空字符串。 height[i]:sa[i-1] 与 sa[i]的LCP(最长公共前缀)值
所以height[1] = 0;
rank[len] = 0;
sa[0] = len;
*/
int sa[N],rnk[N],height[N];
void construct(const char *s,int n,int m = ) {
static int t1[N],t2[N],c[N];
int *x = t1,*y = t2;
int i,j,k,p,l;
for (i = ; i < m; ++ i) c[i] = ;
for (i = ; i < n; ++ i) c[x[i] = s[i]] ++;
for (i = ; i < m; ++ i) c[i] += c[i - ];
for (i = n - ; i >= ; -- i) sa[--c[x[i]]] = i;
for (k = ; k <= n; k <<= ) {
p = ;
for (i = n - k; i < n; ++ i) y[p++] = i;
for (i = ; i < n; ++ i) if (sa[i] >= k) y[p++] = sa[i] - k;
for (i = ; i < m; ++ i) c[i] = ;
for (i = ; i < n; ++ i) c[x[y[i]]] ++;
for (i = ; i < m; ++ i) c[i] += c[i - ];
for (i = n - ; i >= ; -- i) sa[--c[x[y[i]]]] = y[i];
std::swap(x,y);
p = ; x[sa[]] = ;
for (i = ; i < n; ++ i)
x[sa[i]] = y[sa[i - ]] == y[sa[i]]
&& y[sa[i - ] + k] == y[sa[i] + k] ? p - : p ++;
if (p >= n) break;
m = p;
}
for (i = ; i < n; ++ i) rnk[sa[i]] = i;
for (i = ,l = ; i < n; ++ i) {
if (rnk[i]) {
j = sa[rnk[i] - ];
while (s[i + l] == s[j + l]) l++;
height[rnk[i]] = l;
if (l) l--;
}
}
} int m,pos,len;
char s[N];
bool solve(int L)
{
// 用后缀数组的话,如果重复长度就是最长的长度,需要特判
if(m == && L == len) {pos = ; return ;}
pos = -;
int cnt = ;
int temp = -; // 要用一个temp来记录当前cnt>=m的最大的位置
for(int i=;i<=len;i++)
{
if(height[i] >= L) cnt++, temp = max(temp, sa[i]);
else cnt = , temp = sa[i];
if(cnt >= m) pos = max(pos, temp);
}
return pos != -;
} int main()
{
while(scanf("%d",&m) == && m)
{
scanf("%s",s);
len = strlen(s);
construct(s, len+);
int l = , r = len;
int ans = -;
while(l <= r)
{
int mid = l + r >> ;
if(solve(mid)) ans = mid, l = mid + ;
else r = mid - ;
}
solve(ans);
if(ans != -) printf("%d %d\n",r,pos);
else puts("none");
}
return ;
}

SA的写法

  顺便想说一下的是,这里不知为何下标从1开始无限WA,以后用SA还是下标从0开始好了。。毕竟不懂SA的具体原理。

UVALive - 4513 Stammering Aliens ——(hash+二分 || 后缀数组加二分)的更多相关文章

  1. [bzoj1717][Usaco2006 Dec]Milk Patterns 产奶的模式 (hash构造后缀数组,二分答案)

    以后似乎终于不用去学后缀数组的倍增搞法||DC3等blablaSXBK的方法了= = 定义(来自关于后缀数组的那篇国家集训队论文..) 后缀数组:后缀数组SA是一个一维数组,它保存1..n的某个排列S ...

  2. uvalive 4513 Stammering Aliens

    题意:给你一个串,问期中至少出现m次的最长子串及其起始位置的坐标. 思路:hash+LCP+二分答案 #include<cstdio> #include<cstring> #i ...

  3. BZOJ 2946 [Poi2000]公共串 (二分+Hash/二分+后缀数组/后缀自动机)

    求多串的最长公共字串. 法1: 二分长度+hash 传送门 法2: 二分+后缀数组 传送门 法3: 后缀自动机 拿第一个串建自动机,然后用其他串在上面匹配.每次求出SAM上每个节点的最长匹配长度后,再 ...

  4. Hash(LCP) || 后缀数组 LA 4513 Stammering Aliens

    题目传送门 题意:训练指南P225 分析:二分寻找长度,用hash值来比较长度为L的字串是否相等. #include <bits/stdc++.h> using namespace std ...

  5. HDU4080 Stammering Aliens(二分 + 后缀数组)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=4080 Description Dr. Ellie Arroway has establish ...

  6. FJUT3703 这还是一道数论题(二分 + hash + manacher 或者 STL + hash 或者 后缀数组 + hash)题解

    Problem Description 最后来个字符串签个到吧,这题其实并不难,所需的算法比较基础,甚至你们最近还上过课. 为了降低难度,免得所有人爆零.这里给几个提示的关键字 :字符串,回文,二分, ...

  7. 140. 后缀数组(hash + 二分 / 后缀数组)

    题目链接 : https://www.acwing.com/problem/content/description/142/ Hash + 二分 #include <bits/stdc++.h& ...

  8. poj 2774 最长公共子--弦hash或后缀数组或后缀自己主动机

    http://poj.org/problem?id=2774 我想看看这里的后缀数组:http://blog.csdn.net/u011026968/article/details/22801015 ...

  9. 后缀数组LCP + 二分 - UVa 11107 Life Forms

    Life Forms Problem's Link Mean: 给你n个串,让你找出出现次数大于n/2的最长公共子串.如果有多个,按字典序排列输出. analyse: 经典题. 直接二分判断答案. 判 ...

随机推荐

  1. 安装中文版cacti监控华为交换机流量并实现95计费

    摘要:一. 装置yum源: 以网易yum源为例 1. 下载repo文件 下载地点:http://mirrors.163.com/.help/CentOS6-Base-163.repo 2.备份并调换体 ...

  2. 学习opencv

    图像缩放 cv::Mat src_img = cv::imread(); ; cv::Mat dst_img1; cv::Mat dst_img2(src_img.rows*0.5, src_img. ...

  3. js运动框架之一条乱跑的虫子

    克隆与运动框架的联合应用 效果:点击元素块后,元素块开始随机的向任何方向移动,并附带一堆颜色随机的"尾巴".每个方向运动3秒后改变方向,同时笑脸变哭脸. 如图所示: 朝某个方向运动 ...

  4. 浅析c#内存泄漏

    一直以来都对内存泄露和内存溢出理解的不是很深刻.在网上看到了几篇文章,于是整理了一下自己对内存泄露和内存溢出的理解. 一.概念 内存溢出:指程序在运行的过程中,程序对内存的需求超过了超过了计算机分配给 ...

  5. python中的thread

    转载自: http://blog.sina.com.cn/s/blog_9f488855010198vn.html 正确与否未验证 python中得thread的一些机制和C/C++不同:在C/C++ ...

  6. java获取文件夹下文件名

    public static String [] getFileName(String path) { File file = new File(path); String [] fileName = ...

  7. Andriod中textview垂直水平居中及LinearLayout内组件的垂直布局

    1.textview 垂直水平居中的设置 Android:gravity="center_vertical|center" 2.LinearLayout中设置控件垂直布局,默认的是 ...

  8. UDP/TCP

    转载地址http://blog.csdn.net/wwmusic/article/details/8875748 Socket  是一套建立在TCP/IP协议上的接口不是一个协议 应用层:  HTTP ...

  9. android上下文菜单

    XML: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmln ...

  10. Idea CheckStyle 安装

    Idea CheckStyle 安装 1.    安装CheckStyle a)     下载idea checksytle 插件 b)     打开Idea的 Settings –>Plugi ...