acdream1116 Gao the string!(hash二分 or 后缀数组)
问题套了一个斐波那契数,归根结底就是要求对于所有后缀s[i...n-1],所有前缀在其中出现的总次数。我一开始做的时候想了好久,后来看了别人的解法才恍然大悟。对于一个后缀来说 s[i...n-1]来说,所有与它匹配的前缀必然是和 s[i+1...n-1] s[i+2...n-1] ....s[n-1..n-1]里的前缀匹配的,因而如果我们定义一个num[i]表示的是后缀s[i...n-1]与前缀的总长公共前缀,那么num[i]+num[i+1]+..num[n-1]就是前缀在后缀i里出现的次数总和,所以问题转化为求s[i...n-1]跟前缀的最长公共前缀,也可以理解成是 s[0...n-1]和s[i...n-1]求最长公共前缀。
求后缀的最长公共前缀,一个做法是后缀数组,然后建lcp,然后通过rmq询问,理论的复杂度nlogn,我自己套的模板用的是快排,所以后缀数组本身的复杂度就已经是nlog^2n,然后我就愉快的TLE了。
失败之后就只能转而用hash+二分,毕竟二分还是慢,所以我卡着时限过了这题,心有余悸。
#pragma warning(disable:4996)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <string>
#include <algorithm>
using namespace std; #define maxn 110000
#define ll long long
#define mod 1000000007
#define step 31 /*int rk[maxn], sa[maxn], lcp[maxn];
int tmp[maxn];
int d[maxn + 50][25];*/ int n; /*bool cmp_sa(int i, int j)
{
if (rk[i] != rk[j]) return rk[i] < rk[j];
else{
int ri = i + k <= n ? rk[i + k] : -1;
int rj = j + k <= n ? rk[j + k] : -1;
return ri < rj;
}
} void construct_sa(char *s, int *sa)
{
n = strlen(s);
for (int i = 0; i <= n; i++){
sa[i] = i;
rk[i] = i < n ? s[i] : -1;
}
for (k = 1; k <= n; k <<= 1){
sort(sa, sa + n + 1, cmp_sa);
tmp[sa[0]] = 0;
for (int i = 1; i <= n; i++){
tmp[sa[i]] = tmp[sa[i - 1]] + (cmp_sa(sa[i - 1], sa[i]) ? 1 : 0);
}
for (int i = 0; i <= n; i++){
rk[i] = tmp[i];
}
}
} void construct_lcp(char *s, int *sa, int *lcp)
{
n = strlen(s);
for (int i = 0; i <= n; i++) rk[sa[i]] = i;
int h = 0;
lcp[0] = 0;
for (int i = 0; i < n; i++){
int j = sa[rk[i] - 1];
for (h ? h-- : 0; i + h < n&&j + h < n&&s[i + h] == s[j + h]; h++);
lcp[rk[i] - 1] = h;
}
} void construct_rmq(int *lcp, int sizen)
{
for (int i = 0; i <= sizen; i++) d[i][0] = lcp[i];
for (int j = 1; (1 << j) <= sizen; j++){
for (int i = 0; (i + (1 << j) - 1) <= sizen; i++){
d[i][j] = min(d[i][j - 1], d[i + (1 << (j - 1))][j - 1]);
}
}
} int rmq_query(int l, int r)
{
if (l > r) swap(l, r); r -= 1;
int k = 0; int len = r - l + 1;
while ((1 << (k + 1)) < len) k++;
return min(d[l][k], d[r - (1 << k) + 1][k]);
} */ char s[maxn];
ll num[maxn]; struct Matrix
{
ll a[2][2];
Matrix(){ memset(a, 0, sizeof(a)); }
}m; Matrix operator * (const Matrix &a,const Matrix &b){
Matrix ret;
for (int i = 0; i < 2; i++){
for (int j = 0; j < 2; j++){
for (int k = 0; k < 2; k++){
ret.a[i][j] += (a.a[i][k] * b.a[k][j]) % mod;
ret.a[i][j] %= mod;
}
}
}
return ret;
}
Matrix operator ^ (Matrix a,ll n){
Matrix ret;
for (int i = 0; i < 2; i++) ret.a[i][i] = 1;
while (n){
if (n & 1) ret = ret*a;
n >>= 1;
a = a*a;
}
return ret;
} ll cal(ll n)
{
m.a[0][0] = 0; m.a[0][1] = 1;
m.a[1][0] = 1; m.a[1][1] = 1;
m = m^n;
return m.a[0][1];
} ll seed[maxn];
ll h[maxn]; ll get(int l, int r){
return ((h[r] - h[l - 1] * seed[r - l + 1]%mod) + mod) % mod;
} int getlcp(int x)
{
if (get(1, 1) != get(x, x)) return 0;
int l = 1,r = n - x + 1;
while (l <= r){
int m = (l + r) >> 1;
if (get(1, 1 + m - 1) == get(x, x + m - 1)) l = m+1;
else r = m-1;
}
return r;
} int main()
{
seed[0] = 1;
for (int i = 1; i < maxn; i++){
seed[i] = seed[i - 1] * step%mod;
}
while (~scanf("%s", s + 1))
{
n = strlen(s + 1); h[0] = 0;
for (int i = 1; i <= n; i++){
h[i] = (h[i - 1] * step + s[i]) % mod;
}
num[1] = n;
for (int i = 2; i <= n; i++){
num[i] = getlcp(i);
}
ll ans = 0;
num[n + 1] = 0;
for (int i = n; i >= 1; i--){
num[i] += num[i + 1];
ans += cal(num[i]);
ans %= mod;
}
printf("%lld\n", ans);
}
return 0;
}
acdream1116 Gao the string!(hash二分 or 后缀数组)的更多相关文章
- acdream1116 Gao the string!(扩展KMP)
今天是字符串填坑的一天,首先填的第一个坑是扩展KMP.总结一下KMP和扩展KMP的区别. 在这里s是主串,t是模式串. KMP可以求出的是以s[i]为结尾的串和 t前缀匹配的最长的长度.假如这个长度是 ...
- BZOJ 1717: [Usaco2006 Dec]Milk Patterns 产奶的模式( 二分答案 + 后缀数组 )
二分答案m, 后缀数组求出height数组后分组来判断. ------------------------------------------------------------ #include&l ...
- bzoj 4310 跳蚤 二分答案+后缀数组/后缀树
题目大意 给定\(k\)和长度\(\le10^5\)的串S 把串分成不超过\(k\)个子串,然后对于每个子串\(s\),他会从\(s\)的所有子串中选择字典序最大的那一个,并在选出来的\(k\)个子串 ...
- BZOJ3796 Mushroom追妹纸(二分答案+后缀数组+KMP)
求出一个串使得这个串是\(s1,s2\)的子串.串中不包含\(s3\). 如果没有这个\(s3\)就可以二分答案,然后height小于二分值分一组.看看每组里是不是出现过\(s1,s2\)的后缀.判断 ...
- poj 1743 二分答案+后缀数组 求不重叠的最长重复子串
题意:给出一串序列,求最长的theme长度 (theme:完全重叠的子序列,如1 2 3和1 2 3 or 子序列中每个元素对应的差相等,如1 2 3和7 8 9) 要是没有差相等这个条件那就好办 ...
- 2018.11.24 poj1743Musical Theme(二分答案+后缀数组)
传送门 代码: 二分答案. 然后对于预处理的heightheightheight数组分成几段. 保证每一段中都是连续的几个heightheightheight并且这些heightheightheigh ...
- [BZOJ4556][TJOI2016&&HEOI2016]字符串(二分答案+后缀数组+RMQ+主席树)
4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 1360 Solved: 545[S ...
- poj 3261 二分答案+后缀数组 求至少出现k次的最长重复子序列
#include "stdio.h" #define maxn 20010 int wa[maxn],wb[maxn],wv[maxn],ws[maxn]; int rank[ma ...
- 2018.11.24 poj3261Milk Patterns(后缀数组)
传送门 后缀数组经典题. 貌似可以用二分答案+后缀数组? 我自己yyyyyy了一个好写一点的方法. 直接先预处理出heightheightheight数组. 然后对于所有连续的k−1k-1k−1个he ...
随机推荐
- Python脚本控制的WebDriver 常用操作 <四> 设置浏览器大小
下面将使用webdriver来控制浏览器窗口的大小 测试用例场景 设置浏览器窗口的大小有下面两个比较常见的用途: 在统一的浏览器大小下运行用例,可以比较容易的跟一些基于图像比对的工具进行结合,提升测试 ...
- IE10-浏览器实现placeholder效果
如下图,在文本框为空时显示提示文字 在IE10+和chrome浏览器加placeholder属性及可实现 ,单在IE10-浏览器并不支持该属性, 以下是placeholder在IE10-浏览器的实现 ...
- XAML(4) - 标记扩展
在为元素设置值时, 可以直接设置值, 但有时标记扩展非常有帮助.标记扩展包含花括号,其后是定义了标记扩展类型的字符串标志. 下面是一个Static Resource标记扩展: <Button N ...
- opengl基础学习专题 (三) 多边形绘制的几种样式
题外话 聪明人之所以不会成功,是由于他们缺乏坚韧的毅力. ——艾萨克·牛顿(1643年1月4日—1727年3月31日)英国 也许可以理解为 想更深一步的时候,坚持,努力和聪明缺一不可. 挺直腰杆在此向 ...
- MongoDB仲裁节点的理解以及memcached,zookeeper,redis,故障恢复方案思考.
在进行副本集部署时我们会添加一个或多个仲裁节点,仲裁节点不用于备份数据,由于它职责的职责是负责选举主节点,所以对硬件没有太高要求,可以将它部署在单独的服务器上,这个服务器可以是监听服务器,也可以部署在 ...
- Lambda前世今生
1.学习资料 匿名函数 C#编程指南http://msdn.microsoft.com/zh-cn/library/bb882516.aspx Lambda表达式 C#编程指南http://msdn. ...
- PB中无法插入ole控件,解决办法
cmd /c for %i in (%windir%\system32\*.ocx) do regsvr32.exe /s %icmd /c for %i in (%windir%\system32\ ...
- Java-包
定义包用package关键字. 1:对类文件进行分类管理. 2:给类文件提供多层名称空间. 如果生成的包不在当前目录下,需要最好执行classpath,将包所在父目录定义到classpath变量中即可 ...
- c++11并发程序设计(1)
第一章:你好 c++的并发世界 1.何为并发 最简单和最基本的并发,是指两个或两个以上的独立活动同时进行. 对于单个处理单元或者核心,这种机器只能在某一时刻执行一个任务,不够它可以每秒进行多次的任务切 ...
- java 24点算法实现
最近闲来无事,突然怀念起小时候和堂兄表姐们经常玩24点游戏,于是就琢磨着是不是开发一个安卓手机版本.然后上网上一搜,发现已经被别人给开发烂了啊.不过这只能说明这个小游戏要想赚广告费很难了,但是拿来锻炼 ...