UVALive - 4513 Stammering Aliens ——(hash+二分 || 后缀数组加二分)
题意:找一个出现了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+二分 || 后缀数组加二分)的更多相关文章
- [bzoj1717][Usaco2006 Dec]Milk Patterns 产奶的模式 (hash构造后缀数组,二分答案)
以后似乎终于不用去学后缀数组的倍增搞法||DC3等blablaSXBK的方法了= = 定义(来自关于后缀数组的那篇国家集训队论文..) 后缀数组:后缀数组SA是一个一维数组,它保存1..n的某个排列S ...
- uvalive 4513 Stammering Aliens
题意:给你一个串,问期中至少出现m次的最长子串及其起始位置的坐标. 思路:hash+LCP+二分答案 #include<cstdio> #include<cstring> #i ...
- BZOJ 2946 [Poi2000]公共串 (二分+Hash/二分+后缀数组/后缀自动机)
求多串的最长公共字串. 法1: 二分长度+hash 传送门 法2: 二分+后缀数组 传送门 法3: 后缀自动机 拿第一个串建自动机,然后用其他串在上面匹配.每次求出SAM上每个节点的最长匹配长度后,再 ...
- Hash(LCP) || 后缀数组 LA 4513 Stammering Aliens
题目传送门 题意:训练指南P225 分析:二分寻找长度,用hash值来比较长度为L的字串是否相等. #include <bits/stdc++.h> using namespace std ...
- HDU4080 Stammering Aliens(二分 + 后缀数组)
题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=4080 Description Dr. Ellie Arroway has establish ...
- FJUT3703 这还是一道数论题(二分 + hash + manacher 或者 STL + hash 或者 后缀数组 + hash)题解
Problem Description 最后来个字符串签个到吧,这题其实并不难,所需的算法比较基础,甚至你们最近还上过课. 为了降低难度,免得所有人爆零.这里给几个提示的关键字 :字符串,回文,二分, ...
- 140. 后缀数组(hash + 二分 / 后缀数组)
题目链接 : https://www.acwing.com/problem/content/description/142/ Hash + 二分 #include <bits/stdc++.h& ...
- poj 2774 最长公共子--弦hash或后缀数组或后缀自己主动机
http://poj.org/problem?id=2774 我想看看这里的后缀数组:http://blog.csdn.net/u011026968/article/details/22801015 ...
- 后缀数组LCP + 二分 - UVa 11107 Life Forms
Life Forms Problem's Link Mean: 给你n个串,让你找出出现次数大于n/2的最长公共子串.如果有多个,按字典序排列输出. analyse: 经典题. 直接二分判断答案. 判 ...
随机推荐
- 安装中文版cacti监控华为交换机流量并实现95计费
摘要:一. 装置yum源: 以网易yum源为例 1. 下载repo文件 下载地点:http://mirrors.163.com/.help/CentOS6-Base-163.repo 2.备份并调换体 ...
- 学习opencv
图像缩放 cv::Mat src_img = cv::imread(); ; cv::Mat dst_img1; cv::Mat dst_img2(src_img.rows*0.5, src_img. ...
- js运动框架之一条乱跑的虫子
克隆与运动框架的联合应用 效果:点击元素块后,元素块开始随机的向任何方向移动,并附带一堆颜色随机的"尾巴".每个方向运动3秒后改变方向,同时笑脸变哭脸. 如图所示: 朝某个方向运动 ...
- 浅析c#内存泄漏
一直以来都对内存泄露和内存溢出理解的不是很深刻.在网上看到了几篇文章,于是整理了一下自己对内存泄露和内存溢出的理解. 一.概念 内存溢出:指程序在运行的过程中,程序对内存的需求超过了超过了计算机分配给 ...
- python中的thread
转载自: http://blog.sina.com.cn/s/blog_9f488855010198vn.html 正确与否未验证 python中得thread的一些机制和C/C++不同:在C/C++ ...
- java获取文件夹下文件名
public static String [] getFileName(String path) { File file = new File(path); String [] fileName = ...
- Andriod中textview垂直水平居中及LinearLayout内组件的垂直布局
1.textview 垂直水平居中的设置 Android:gravity="center_vertical|center" 2.LinearLayout中设置控件垂直布局,默认的是 ...
- UDP/TCP
转载地址http://blog.csdn.net/wwmusic/article/details/8875748 Socket 是一套建立在TCP/IP协议上的接口不是一个协议 应用层: HTTP ...
- android上下文菜单
XML: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmln ...
- Idea CheckStyle 安装
Idea CheckStyle 安装 1. 安装CheckStyle a) 下载idea checksytle 插件 b) 打开Idea的 Settings –>Plugi ...